initial commit, lordsawar source, slightly modified
[lordsawar] / src / MapGenerator.cpp
diff --git a/src/MapGenerator.cpp b/src/MapGenerator.cpp
new file mode 100644 (file)
index 0000000..aa7f51f
--- /dev/null
@@ -0,0 +1,1861 @@
+// Copyright (C) 2002 Vibhu Rishi
+// Copyright (C) 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
+// Copyright (C) 2004 David Barnsdale
+// Copyright (C) 2003 Michael Bartl
+// Copyright (C) 2004, 2005 Andrea Paternesi
+// Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
+// Copyright (C) 2008 Janek Kozicki
+//
+//  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 Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 
+//  02110-1301, USA.
+
+#include <stdlib.h>
+#include <iostream>
+#include <math.h>  
+#include <algorithm>
+#include <set>
+#include <string.h>
+
+//#include <boost/foreach.hpp>
+
+#include "MapGenerator.h"
+#include "GameMap.h"
+#include "stack.h"
+#include "path.h"
+#include "File.h"
+#include "citylist.h"
+#include "city.h"
+#include "roadlist.h"
+#include "road.h"
+#include "portlist.h"
+#include "port.h"
+#include "ruinlist.h"
+#include "ruin.h"
+#include "templelist.h"
+#include "temple.h"
+#include "bridgelist.h"
+#include "bridge.h"
+#include "armysetlist.h"
+#include "army.h"
+#include "vector.h"
+#include "RoadPathCalculator.h"
+#include "cityset.h"
+
+#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
+//#define debug(x)
+#define offmap(bx,by) (by<0)||(by>=d_height)||(bx<0)||(bx>=d_width)
+
+using namespace std;
+
+//-------------------------------------------------------------------
+
+MapGenerator::MapGenerator()
+    //set reasonable default values
+    :d_terrain(0), d_building(0), d_pswamp(2), d_pwater(25), d_pforest(3),
+    d_phills(5), d_pmountains(5), d_nocities(11), d_notemples(9), d_noruins(20),
+    d_nosignposts(30), cityset(NULL)
+
+{
+    d_xdir[0]=0;d_xdir[1]=-1;d_xdir[2]=-1;d_xdir[3]=-1;d_xdir[4]=0;d_xdir[5]=1;d_xdir[6]=1;d_xdir[7]=1;
+    d_ydir[0]=-1;d_ydir[1]=-1;d_ydir[2]=0;d_ydir[3]=1;d_ydir[4]=1;d_ydir[5]=1;d_ydir[6]=0;d_ydir[7]=-1;
+}
+
+MapGenerator::~MapGenerator()
+{
+    if (d_terrain)
+        delete[] d_terrain;
+    if (d_building)
+        delete[] d_building;
+}
+
+int MapGenerator::setNoCities(int nocities)
+{
+    if (nocities <= 0)
+        return -1;
+
+    int tmp = d_nocities;
+    d_nocities = nocities;
+    return tmp;
+}
+
+int MapGenerator::setNoRuins(int noruins)
+{
+    if (noruins < 0)
+        return -1;
+
+    int tmp = d_noruins;
+    d_noruins = noruins;
+    return tmp;
+}
+
+int MapGenerator::setNoSignposts(int nosignposts)
+{
+    if (nosignposts < 0)
+        return -1;
+
+    int tmp = d_nosignposts;
+    d_nosignposts = nosignposts;
+    return tmp;
+}
+
+int MapGenerator::setNoTemples(int notemples)
+{
+    if (notemples < 0)
+        return -1;
+
+    int tmp = d_notemples;
+    d_notemples = notemples;
+    return tmp;
+}
+
+void MapGenerator::setPercentages(int pwater, int pforest, int pswamp,
+                                    int phills, int pmountains)
+{
+    if ((pswamp < 0) || (pwater < 0) || (pforest < 0) || (phills < 0)
+        || (pmountains < 0))
+        return;
+
+    if (pswamp + pwater + pforest + phills + pmountains > 100)
+        return;
+
+    d_pswamp = pswamp;
+    d_pwater = pwater;
+    d_pforest = pforest;
+    d_phills = phills;
+    d_pmountains = pmountains;
+}
+
+/** 
+ * Generates a random map . The map is stored as a char array of size 
+ * 100x100. Each character stands for something. We use :
+ * M = mountains
+ * h = hills
+ * ~ = water
+ * $ = forest
+ * . = plains
+ * _ = swamps
+ * C = city/castle
+ * r = ruins
+ * T = temple
+ *   = nothing
+ * c = part of city/castle
+ * See the TileMapTypes enum at the beginning of the class definition.
+ *
+ * See printMap() which is used for debugging maps.
+ */
+void MapGenerator::makeMap(int width, int height, bool roads)
+{
+    d_width = width;
+    d_height = height;
+
+    //initialize terrain and building arrays
+    d_terrain = new Tile::Type[width*height];
+    d_building = new Maptile::Building[width*height];
+    for (int i = 0; i < height; i++)
+        for (int j = 0; j < width; j++)
+            d_building[i*width + j] = Maptile::NONE;
+
+    debug("Making random map:");
+   
+    // create the terrain
+    debug("flatening plains");
+    progress.emit(.090, _("flattening plains..."));
+    makePlains();
+    debug("raining water");
+    progress.emit(.180, _("raining water..."));
+    makeTerrain(Tile::WATER, d_pwater, true);  
+    makeStreamer(Tile::WATER, d_pwater/3, 3);
+    rescueLoneTiles(Tile::WATER,Tile::GRASS,true);
+    makeRivers();
+    verifyIslands();
+    debug("raising hills");
+    progress.emit(.270, _("raising hills..."));
+    makeTerrain(Tile::HILLS, d_phills, false);
+    debug("raising mountains");
+    progress.emit(.360, _("raising mountains..."));
+    makeTerrain(Tile::MOUNTAIN, d_pmountains, false);
+    makeStreamer(Tile::MOUNTAIN, d_pmountains/3, 3);
+    rescueLoneTiles(Tile::MOUNTAIN,Tile::GRASS,false);
+    surroundMountains(0, d_width, 0, d_height);
+    debug("planting forest");
+    progress.emit(.450, _("planting forests..."));
+    makeTerrain(Tile::FOREST, d_pforest, false);
+    debug("watering swamps");
+    progress.emit(.540, _("watering swamps..."));
+    makeTerrain(Tile::SWAMP, d_pswamp, false);
+    debug("normalizing terrain");
+    progress.emit(.630, _("normalizing terrain..."));
+    normalize();
+
+    // place buildings
+    debug("building cities");
+    progress.emit(.720, _("building cities..."));
+    makeCities(d_nocities);
+
+    if (roads)
+      {
+       debug("paving roads");
+       progress.emit(.810, _("paving roads..."));
+       makeRoads();
+      }
+    rescueLoneTiles(Tile::MOUNTAIN,Tile::HILLS,false);
+
+    debug("ruining ruins");
+    progress.emit(.810, _("ruining ruins..."));
+    makeBuildings(Maptile::RUIN,d_noruins);
+    debug("spawning temples");
+    progress.emit(.900, _("spawning temples..."));
+    makeBuildings(Maptile::TEMPLE,d_notemples);
+    debug("building bridges");
+    if (roads == true)
+      {
+        progress.emit(.950, _("building bridges..."));
+        makeBridges();
+      }
+    debug("raising signs");
+    progress.emit(.990, _("raising signs..."));
+    makeBuildings(Maptile::SIGNPOST,d_nosignposts);
+
+    debug("Done making map.");
+
+//    printMap();
+}
+        
+#define  NORTH_SOUTH_BRIDGE 1
+#define  EAST_WEST_BRIDGE 2
+
+void MapGenerator::placeBridge(Vector<int> pos, int type)
+{
+  Bridgelist *bl = Bridgelist::getInstance();
+  if (type == NORTH_SOUTH_BRIDGE)
+    {
+      d_building[pos.y*d_width + pos.x] = Maptile::BRIDGE;
+      d_building[(pos.y + 1)*d_width + pos.x] = Maptile::BRIDGE;
+      bl->add(new Bridge(Vector<int>(pos.x, pos.y)));
+      bl->add(new Bridge(Vector<int>(pos.x+1, pos.y)));
+    }
+  else if (type == EAST_WEST_BRIDGE)
+    {
+      d_building[pos.y*d_width + pos.x] = Maptile::BRIDGE;
+      d_building[pos.y*d_width + pos.x + 1] = Maptile::BRIDGE;
+      bl->add(new Bridge(Vector<int>(pos.x, pos.y)));
+      bl->add(new Bridge(Vector<int>(pos.x, pos.y+1)));
+    }
+  GameMap::getInstance()->calculateBlockedAvenues();
+}
+
+bool MapGenerator::findBridgePurpose(Vector<int> pos, int type, 
+                                    Vector<int> &src, Vector<int> &dest)
+{
+  if (type == EAST_WEST_BRIDGE)
+    {
+      src = GameMap::getInstance()->findNearestObjectToTheWest(pos);
+      dest = GameMap::getInstance()->findNearestObjectToTheEast(pos);
+    }
+  else if (type == NORTH_SOUTH_BRIDGE)
+    {
+      src = GameMap::getInstance()->findNearestObjectToTheNorth(pos);
+      dest = GameMap::getInstance()->findNearestObjectToTheSouth(pos);
+    }
+  if (src == Vector<int>(-1,-1) || dest == Vector<int>(-1,-1))
+    return false;
+  return true;
+}
+
+bool MapGenerator::canPlaceBridge(Vector<int> pos, int type, Vector<int> &src, Vector<int> &dest)
+{
+  if (d_building[pos.y*d_width + pos.x] == Maptile::NONE &&
+      findBridgePurpose(pos, type, src, dest) == true)
+    return true;
+  return false;
+}
+
+void MapGenerator::makeBridges()
+{
+  GameMap::deleteInstance();
+  Citylist::deleteInstance();
+  Roadlist::deleteInstance();
+  Ruinlist::deleteInstance();
+  Templelist::deleteInstance();
+  Portlist::deleteInstance();
+  Bridgelist::deleteInstance();
+
+  GameMap::setWidth(d_width);
+  GameMap::setHeight(d_height);
+  GameMap::getInstance("default", "default", "default")->fill(this);
+
+  //the game map class smooths the map, so let's take what it smoothed.
+  for (int y = 0; y < d_height; y++)
+    for (int x = 0; x < d_width; x++)
+      d_terrain[y*d_width + x] = 
+       GameMap::getInstance()->getTile(x, y)->getMaptileType();
+
+  //load up the roadlist, and stuff.
+
+  for (int y = 0; y < d_height; y++)
+    for (int x = 0; x < d_width; x++)
+      {
+       if (d_building[y*d_width + x] == Maptile::CITY)
+         Citylist::getInstance()->add
+           (new City(Vector<int>(x,y), cityset->getCityTileWidth()));
+       else if (d_building[y*d_width + x] == Maptile::ROAD)
+         Roadlist::getInstance()->add(new Road(Vector<int>(x,y)));
+       else if (d_building[y*d_width + x] == Maptile::RUIN)
+         Ruinlist::getInstance()->add
+           (new Ruin(Vector<int>(x,y), cityset->getRuinTileWidth()));
+       else if (d_building[y*d_width + x] == Maptile::TEMPLE)
+         Templelist::getInstance()->add
+           (new Temple(Vector<int>(x,y), cityset->getTempleTileWidth()));
+       else if (d_building[y*d_width + x] == Maptile::PORT)
+         Portlist::getInstance()->add(new Port(Vector<int>(x,y)));
+      }
+  GameMap::getInstance()->calculateBlockedAvenues();
+
+  Vector<int> src, dest;
+  std::vector<pair<int , Vector<int> > >  bridges;
+  bridges = findBridgePlaces();
+  for (std::vector<pair<int, Vector<int> > >::iterator it = bridges.begin();
+       it != bridges.end(); it++)
+    {
+      Vector<int> pos = (*it).second + Vector<int>(1,1);
+      Vector<int> edge1; 
+      Vector<int> edge2; 
+      if ((*it).first == NORTH_SOUTH_BRIDGE)
+       {
+         edge1 = pos - Vector<int>(0, 1);
+         edge2 = pos + Vector<int>(0, 2);
+       }
+      else if ((*it).first == EAST_WEST_BRIDGE)
+       {
+         edge1 = pos - Vector<int>(1, 0);
+         edge2 = pos + Vector<int>(2, 0);
+       }
+      if (offmap(edge1.x, edge1.y) || offmap(edge2.x, edge2.y))
+       continue;
+      if (canPlaceBridge((*it).second + Vector<int>(1,1), (*it).first, src, 
+                        dest) == true)
+       {
+         int leg1 = tryRoad (src, edge1);
+         int leg2 = tryRoad (dest, edge2);
+         int shortcut = tryRoad (src, dest);
+         bool construct_bridge_and_roads = true;
+         if (leg1 <= 0 || leg2 <= 0)
+           construct_bridge_and_roads = false;
+         if (shortcut > 0 && (leg1 + leg2 + 2) > shortcut)
+           construct_bridge_and_roads = false;
+
+         if (construct_bridge_and_roads)
+           {
+             makeRoad(src, edge1);
+             makeRoad(dest, edge2);
+             placeBridge(pos, (*it).first);
+           }
+       }
+       progress.emit(.950, _("paving bridges..."));
+    }
+
+  Roadlist::deleteInstance();
+  Ruinlist::deleteInstance();
+  Templelist::deleteInstance();
+  GameMap::deleteInstance();
+  Citylist::deleteInstance();
+  Portlist::deleteInstance();
+  Bridgelist::deleteInstance();
+}
+
+void MapGenerator::printMap(int j, int i)
+{
+    char ch='?';
+    bool adom_convention=true; // well, except mountains
+    switch(d_terrain[j*d_width + i])
+    {
+        case Tile::MOUNTAIN:  ch=adom_convention ? 'M' : 'M';break; // mountains
+        case Tile::HILLS   :  ch=adom_convention ? '~' : 'h';break; // hills
+        case Tile::WATER   :  ch=adom_convention ? '=' : '~';break; // water
+        case Tile::FOREST  :  ch=adom_convention ? '&' : '$';break; // forest
+        case Tile::GRASS   :  ch=adom_convention ? '.' : '.';break; // plains
+        case Tile::SWAMP   :  ch=adom_convention ? '"' : '_';break; // swamps
+        case Tile::VOID    :  ch=adom_convention ? '?' : '?';break;
+
+            // cannot print those, actually because they don't exist in Tile::Type
+            //     ch='C';break; // city/castle
+            //     ch='r';break; // ruins
+            //     ch='T';break; // temple
+            //     ch=' ';break; // nothing
+            //     ch='c';break; // part of city/castle
+    }
+    std::cout << ch;
+}
+
+void MapGenerator::printMap()
+{
+    for(int j = 0; j < d_height; j++)
+    {
+        for(int i = 0; i < d_width; i++)
+            printMap(j,i);
+        std::cout << "\n";
+    }
+    std::cout << "\n";
+}
+
+const Tile::Type* MapGenerator::getMap(int& width, int& height) const
+{
+    width = d_width;
+    height = d_height;
+    return d_terrain;
+}
+
+const Maptile::Building* MapGenerator::getBuildings(int& width, int& height) const
+{
+    width = d_width;
+    height = d_height;
+    return d_building;
+}
+
+void MapGenerator::makePlains()
+{
+    for(int j = 0; j < d_height; j++)
+        for(int i = 0; i < d_width; i++)
+            d_terrain[j*d_width + i] = Tile::GRASS;
+}
+
+void MapGenerator::connectWithWater(Vector<int> from, Vector<int> to)
+{
+    Vector<float> delta = from - to;
+    if (dist<float>(from,to) > (float)(d_width*0.4))
+        // we don't want to mess up whole map with straight lines
+        return;
+
+    int kind(rand()%4);
+    delta /= length(delta)*2;
+    for(Vector<float>path = Vector<float>(from)+delta*4 ; dist<float>(path,Vector<float>(to)-delta*4) > 0.5 ; path -= delta)
+    {
+        int j = (int)(path.x);
+        int i = (int)(path.y);
+
+        if(rand()%3 == 0) 
+            kind = rand()%4;
+        switch(kind)
+        {
+            case 0:
+                if((!(offmap(i,j))) && (!(offmap(i-1,j-1))))
+                {
+                    d_terrain[(j  )*d_width + i  ] = Tile::WATER;
+                    d_terrain[(j-1)*d_width + i-1] = Tile::WATER;
+                    d_terrain[(j  )*d_width + i-1] = Tile::WATER;
+                    d_terrain[(j-1)*d_width + i  ] = Tile::WATER;
+                }; break;
+
+            case 1:
+                if((!(offmap(i,j))) && (!(offmap(i+1,j+1))))
+                {
+                    d_terrain[(j  )*d_width + i  ] = Tile::WATER;
+                    d_terrain[(j+1)*d_width + i+1] = Tile::WATER;
+                    d_terrain[(j  )*d_width + i+1] = Tile::WATER;
+                    d_terrain[(j+1)*d_width + i  ] = Tile::WATER;
+                }; break;
+
+            case 2:
+                if((!(offmap(i,j))) && (!(offmap(i-1,j+1))))
+                {
+                    d_terrain[(j  )*d_width + i  ] = Tile::WATER;
+                    d_terrain[(j+1)*d_width + i-1] = Tile::WATER;
+                    d_terrain[(j  )*d_width + i-1] = Tile::WATER;
+                    d_terrain[(j+1)*d_width + i  ] = Tile::WATER;
+                }; break;
+
+            case 3:
+                if((!(offmap(i,j))) && (!(offmap(i+1,j-1))))
+                {
+                    d_terrain[(j  )*d_width + i  ] = Tile::WATER;
+                    d_terrain[(j-1)*d_width + i+1] = Tile::WATER;
+                    d_terrain[(j  )*d_width + i+1] = Tile::WATER;
+                    d_terrain[(j-1)*d_width + i  ] = Tile::WATER;
+                }; break;
+        }
+    }
+}
+
+void MapGenerator::findAreasOf(Tile::Type THIS_TILE,std::vector<std::vector<int> >& box,int& how_many)
+{
+    box.resize(d_height);
+    for(int j = 0; j < d_height; j++)
+        box[j].resize(d_width,0);
+
+    // find all enclosed areas by scanning the map
+    // distinct areas have different numbers in box
+    for(int j = 1; j < d_height-1; j++)
+        for(int i = 1; i < d_width-1; i++)
+            if (box[j][i]==0 &&
+                    d_terrain[j*d_width + i] == THIS_TILE &&
+                    (
+                     (d_terrain[(j-1)*d_width + i-1] == THIS_TILE &&
+                      d_terrain[(j  )*d_width + i-1] == THIS_TILE &&
+                      d_terrain[(j-1)*d_width + i  ] == THIS_TILE)  ||
+
+                     (d_terrain[(j-1)*d_width + i  ] == THIS_TILE &&
+                      d_terrain[(j-1)*d_width + i+1] == THIS_TILE &&
+                      d_terrain[(j  )*d_width + i+1] == THIS_TILE) ||
+
+                     (d_terrain[(j  )*d_width + i+1] == THIS_TILE &&
+                      d_terrain[(j+1)*d_width + i+1] == THIS_TILE &&
+                      d_terrain[(j+1)*d_width + i  ] == THIS_TILE) ||
+
+                     (d_terrain[(j+1)*d_width + i  ] == THIS_TILE &&
+                      d_terrain[(j+1)*d_width + i-1] == THIS_TILE &&
+                      d_terrain[(j  )*d_width + i-1] == THIS_TILE))
+               )
+            {
+                box[j][i]=++how_many+3000;
+                int counter=1;
+                while(counter != 0)
+                {
+                    counter=0;
+                    for(int J = 1; J < d_height-1; J++)
+                        for(int I = 1; I < d_width-1; I++)
+                        {
+                            if(d_terrain[J*d_width + I] == THIS_TILE &&
+                                    box[J][I]    ==0 &&
+                                    (box[J-1][I  ]==how_many+3000 ||
+                                     box[J  ][I-1]==how_many+3000 ||
+                                     box[J  ][I+1]==how_many+3000 ||
+                                     box[J+1][I  ]==how_many+3000))
+                            {
+                                ++counter;
+                                box[J][I]=how_many+2000;
+                            }
+                        }
+                    for(int J = 0; J < d_height; J++)
+                        for(int I = 0; I < d_width; I++)
+                        {
+                            if (box[J][I]==how_many+3000)
+                                box[J][I]=how_many;
+                            if (box[J][I]==how_many+2000)
+                                box[J][I]=how_many+3000;
+                        }
+                }
+            }
+}
+
+void MapGenerator::verifyIslands()
+{
+    int how_many=0;
+    std::vector<std::vector<int> > box;
+    findAreasOf(Tile::GRASS,box,how_many);
+
+    // count the size of each area
+    std::vector<float> counts;
+    counts.resize(how_many+2,0);
+    for(int j = 0; j < d_height; j++)
+        for(int i = 0; i < d_width; i++)
+            if(box[j][i] != 0)
+                counts[box[j][i]] += 1;
+
+    // find four largest land areas
+    std::set<int> largest;largest.clear();
+    int max;
+    for(int z=0 ; z<4 ; ++z)
+    {
+        max = -1;
+        for(size_t i=0 ; i<counts.size() ; ++i)
+        {
+            if(counts[i] > max && largest.find(counts[i]) == largest.end())
+                max = counts[i];
+        }
+        largest.insert(max);
+    }
+
+    // largest are good. Also one/third of all others is good:
+    std::set<int> good(largest);
+    for(size_t i=0 ; i<counts.size() ; ++i)
+        if(rand()%3 == 0) // that's one/third here
+            good.insert(counts[i]);
+
+    // now, eliminate all land that is not good
+    for(int I=0 ; I<(int)(counts.size()) ; ++I)
+        if(good.find(counts[I]) == good.end())
+            for(int j = 1; j < d_height-1; j++)
+                for(int i = 1; i < d_width-1; i++)
+                    if(box[j][i] == I)
+                        d_terrain[j*d_width + i] = Tile::WATER;
+}
+
+void MapGenerator::makeRivers()
+{
+    // river style:
+    //  1 - plenty of short rivers and islands
+    //  2 - longer rivers, less islands
+    //  3 - even longer rivers, even less islands
+    int river_style=rand()%3+1;
+
+    // count how many separate bodies of water were found
+    int how_many;
+
+    int iter=0; // avoid deadlocks
+    while(++iter < 20)
+    {
+        how_many=0;
+
+        std::vector<std::vector<int> > box;
+        
+        findAreasOf(Tile::WATER,box,how_many);
+
+        // this loop allows maximum 3 distinctly separated bodies of water
+        // so no need to continue the algorithm
+        if(how_many<4)
+            break;
+
+        // find two biggest bodies of water, and calculate centers for all of them
+        std::vector< Vector<float> > centers;
+        centers.resize(how_many+2,Vector<float>(0,0));
+        std::vector<float> counts;
+        counts.resize(how_many+2,0);
+        for(int j = 0; j < d_height; j++)
+            for(int i = 0; i < d_width; i++)
+                if(box[j][i] != 0)
+                {
+                    counts[box[j][i]] += 1;
+                    centers[box[j][i]] += Vector<float>(j,i);
+                }
+        // divide sum by counts to get a center
+        int max_count=0,max_count_2=0;
+        for(int h = 0; h < how_many+2; ++h)
+        {
+            if(counts[h]>0)
+            {
+                centers[h] /= counts[h];
+                if(max_count < (int)(counts[h]))
+                    max_count = (int)(counts[h]);
+                if(max_count_2 < (int)(counts[h]) && (int)(counts[h]) != max_count)
+                    max_count_2 = (int)(counts[h]);
+                int J=(int)(centers[h].x), I=(int)(centers[h].y);
+                if(box[J][I] != h)
+                // center doesn't necessarily fall on water tile, so fix this.
+                {
+                    //      // for debugging...
+                    //      box[J][I]+=5000;
+                    int i_up=0,i_dn=0,j_up=0,j_dn=0;
+                    while((I+i_up <  d_width-1 ) && (box[J     ][I+i_up] != h)) ++i_up;
+                    while((I-i_dn >  0         ) && (box[J     ][I-i_dn] != h)) ++i_dn;
+                    while((J+j_up <  d_height-1) && (box[J+j_up][I     ] != h)) ++j_up;
+                    while((J-j_dn >  0         ) && (box[J-j_dn][I     ] != h)) ++j_dn;
+
+                    int shortest = std::min( std::min(i_up,i_dn) , std::min(j_up,j_dn));
+
+                    if(shortest == i_up && I+i_up <  d_width)
+                        centers[h] = Vector<float>( J      , I+i_up );
+                    else
+                        if(shortest == i_dn && I-i_dn >= 0      )
+                            centers[h] = Vector<float>( J      , I-i_dn );
+                        else
+                            if(shortest == j_up && J+j_up <  d_height)
+                                centers[h] = Vector<float>( J+j_up , I      );
+                            else
+                                if(shortest == j_dn && J-j_dn >= 0       )
+                                    centers[h] = Vector<float>( J+j_dn , I      );
+                                else
+                                {
+                                    std::cout << "Sages are wondering about unforeseen mysteries behind the edge of the world.\n";
+                                    counts[h] = -1; // that's ok, but an interesting case. I'd like to see a map with such water :)
+                                    // FIXME - can you make a message box here?
+                                    //MessageBox("Message from author: this is algorithmically a very interesting map, please make screenshot and send to cosurgi@gmail.com");
+                                }
+                }
+                //      // for debugging...
+                //      box[(int)(centers[h].x)][(int)(centers[h].y)]+=4000;
+            }
+        }
+
+        // determine what are the biggest bodies of water here
+        int the_biggest_area=0,second_biggest_area=0;
+        for(int h = 0; h < how_many+2; ++h)
+        {
+            if(counts[h]==max_count   && max_count   != 0)
+                the_biggest_area = h;
+            if(counts[h]==max_count_2 && max_count_2 != 0)
+                second_biggest_area = h;
+        }
+
+        // find shortest distances between areas
+        std::vector<std::vector<std::pair<float, std::pair<Vector<int>, Vector<int> > > > > distances; // I would prefer boost::tuple, but oh well...
+        distances.resize(how_many+2);
+        for(int h = 0; h < how_many+2; ++h)
+        {
+            distances[h].resize(how_many+3,std::make_pair(0,std::make_pair(Vector<int>(0,0),Vector<int>(0,0))));
+            for(int k = h+1; k < how_many+2; ++k)
+            {
+                if(counts[h] > 0 && counts[k] > 0) // h and k are two different areas
+                {
+                    // find tile from area h closest to the center of k 
+                    float min_dist = d_height*d_height;
+                    float min_h_j=0,min_h_i=0;
+                    for(int j = 1; j < d_height-1; j++)
+                        for(int i = 1; i < d_width-1; i++)
+                            if(box[j][i] == h)
+                            {
+                                float dj = j - centers[k].x;
+                                float di = i - centers[k].y;
+                                float dist = dj*dj + di*di;
+                                if(dist < min_dist)
+                                {
+                                    min_dist = dist;
+                                    min_h_j = j;
+                                    min_h_i = i;
+                                }
+                            }
+
+                    // then find tile from area k closest to that tile from h
+                    min_dist = d_height * d_height;
+                    float min_k_j=0,min_k_i=0;
+                    for(int j = 1; j < d_height-1; j++)
+                        for(int i = 1; i < d_width-1; i++)
+                            if(box[j][i] == k)
+                            {
+                                float dj = j - min_h_j;
+                                float di = i - min_h_i;
+                                float dist = dj*dj + di*di;
+                                if(dist < min_dist)
+                                {
+                                    min_dist = dist;
+                                    min_k_j = j;
+                                    min_k_i = i;
+                                }
+                            }
+
+                    if (min_k_j != 0 && 
+                            min_h_j != 0 && 
+                            min_k_i != 0 && 
+                            min_h_i != 0)
+                    {
+                        float dj = min_k_j - min_h_j;
+                        float di = min_k_i - min_h_i;
+                        distances[h][k] = std::make_pair(dj*dj + di*di , std::make_pair(Vector<int>(min_h_j,min_h_i) , Vector<int>(min_k_j,min_k_i)) );
+                    }
+                }
+            }
+        }
+
+        for(int connect_some_closest=0; connect_some_closest<14; connect_some_closest+=river_style)
+        {
+            // if river_style is 1 then
+            //   connect 10 closest to each other, and 4 closest to two biggest bodies of water
+            // otherwise skip some - connect fewer of them.
+            int closest_h=-1,closest_k=-1,min=d_height*d_height;
+            int start_h=0;
+            if(connect_some_closest < 2 ) start_h=the_biggest_area;
+            else
+                if(connect_some_closest < 4) start_h=second_biggest_area;
+            for(int h = start_h; h < ((connect_some_closest >= 4) ? (how_many+2) : start_h+1); ++h)
+                for(int k = h+1; k < how_many+2; ++k)
+                    if(counts[h] > 0 && counts[k] > 0)
+                        if(distances[h][k].first > 0 && min > distances[h][k].first)
+                        {
+                            min = distances[h][k].first;
+                            closest_h = h;
+                            closest_k = k;
+                        }
+            if (closest_h != -1 &&
+                closest_k != -1)
+            {
+                connectWithWater(distances[closest_h][closest_k].second.first , distances[closest_h][closest_k].second.second);
+                // mark as done:
+                distances[closest_h][closest_k].first = d_height*d_height;
+            }
+        }
+        //          // for debugging...   print whole box
+        //          std::cerr << how_many << " separate bodies of water found.\n";
+        //          std::cerr << the_biggest_area << " is the biggest\n";
+        //          std::cerr << second_biggest_area << " is second in size\n";
+        //          std::vector<int> a;
+        //          BOOST_FOREACH(a,box)
+        //          {
+        //              BOOST_FOREACH(int i,a)
+        //              {
+        //                  if(i<4000)
+        //                      std::cout << i << " ";
+        //                  else
+        //                      if(i<5000)
+        //                      std::cout << "X" << " ";
+        //                      else
+        //                      if(i<7000)
+        //                      std::cout << "%" << " ";
+        //                      else
+        //                      if(i<14000)
+        //                      std::cout << "!" << " ";
+        //                      else
+        //                      std::cout << "|" << " ";
+        //              }
+        //              std::cout << "\n";
+        //          }
+        //          std::cout << "\n";
+
+    };
+    //if(how_many>1)
+        //std::cout << "There are " << how_many << (how_many<4?(std::string(" seas")):(std::string(" lakes"))) << " on this map.\n";
+    //else
+        //std::cout << "There is 1 sea on this map.\n";
+    //std::cout << "River style was: " << river_style << "\n";
+}
+
+
+/**
+ * Makes Terrains.
+ * The algorithm is as follows :
+ * 1. Find a random starting location
+ * 2. chose a random direction , if x is the starting location, the direction
+ *    can be from 0-7 as follows :
+ *    +-+-+-+
+ *    |0|1|2|
+ *    +-+-+-+
+ *    |7|x|3|
+ *    +-+-+-+
+ *    |6|5|4|
+ *    +-+-+-+
+ * 3. Check if there is some other terrain there ('.' = plains is okay)
+ * 4. Move one tile in this direction, mutate the tile and continue with 2
+ * 5. If we hit a dead end (all directions non-grass), continue with 1
+ */
+void MapGenerator::makeTerrain(Tile::Type t, int percent, bool contin)
+{
+    // calculate the total number of tiles for this terrain
+    int terrain = d_width*d_height*percent / 100;
+    int placed = 0;  // total of current terrain placed so far 
+    
+    while(placed != terrain)
+    {
+        // find a random starting position
+        int x = rand() % d_width;
+        int y = rand() % d_height;
+        if (seekPlain(x, y) == false)
+          continue;
+
+
+        // now go on until we hit a dead end
+        while (placed < terrain)
+        {
+            // if we are on grass, modify this tile first
+            if (d_terrain[y*d_width + x] == Tile::GRASS)
+            {
+                d_terrain[y*d_width + x] = t;
+                placed++;
+                continue;
+            }
+            
+            // from a random direction, check all directions for further progress
+            int loop = 0;
+            for (int dir = rand()%8; loop < 8; loop++, dir = (dir+1)%8)
+            {
+                int tmpx = x + d_xdir[dir];
+                int tmpy = y + d_ydir[dir];
+                
+                // reject invalid data
+                if (offmap(tmpx, tmpy) || d_terrain[tmpy*d_width + tmpx] != Tile::GRASS)
+                    continue;
+
+                // else move our region of interest by one tile
+                x = tmpx;
+                y = tmpy;
+                d_terrain[y*d_width + x] = t;
+                placed++;
+                break;
+            }
+
+            // we have hit a dead end, i.e. we are only surrounded by non-grass
+            // tiles. Either choose a new random starting point or, if contin
+            // is set, find a close one via seekPlain()
+            if (loop == 8)
+            {
+                if (contin)
+                  {
+                    if (seekPlain(x, y) == false)
+                      continue;
+                  }
+                else
+                    break;
+            }
+        }
+    }
+}
+
+/**
+ * Makes streaming terrain features.
+ * The algorithm is as follows :
+ * 1. Find a random starting location
+ * 2. chose a random direction , if x is the starting location, the direction
+ *    can be from 0-7 as follows :
+ *    +-+-+-+
+ *    |0|1|2|
+ *    +-+-+-+
+ *    |7|x|3|
+ *    +-+-+-+
+ *    |6|5|4|
+ *    +-+-+-+
+ * 3. Drop the tile and move in the direction
+ * 4. Change the direction every so often
+ * 5. Keep doing this until we go off the map or we've dropped enough tiles
+ *
+ */
+void MapGenerator::makeStreamer(Tile::Type t, int percent, int thick)
+{
+    // calculate the total number of tiles for this terrain
+    int terrain = d_width*d_height*percent / 100;
+    int placed = 0;  // total of current terrain placed so far 
+    int dir;
+    int i;
+    
+    while(placed < terrain)
+    {
+        // find a random starting position
+        int x = rand() % d_width;
+        int y = rand() % d_height;
+        if (seekPlain(x, y) == false)
+          continue;
+        dir = rand()%8; // pick a random direction
+        // now go on until we hit a dead end
+        while (placed < terrain)
+        {
+            // if we are on grass, modify this tile first
+            if (d_terrain[y*d_width + x] == Tile::GRASS)
+            {
+                d_terrain[y*d_width + x] = t;
+                placed++;
+                continue;
+            }
+            
+            if (rand() % 2 == 0)
+              {
+                if (rand() % 2 == 0)
+                  {
+                    dir++;
+                    if (dir > 7)
+                      dir = 0;
+                  }
+                else
+                  {
+                    dir--;
+                    if (dir < 0)
+                      dir = 7;
+                  }
+            }
+
+            {
+                int tmpx = x + d_xdir[dir];
+                int tmpy = y + d_ydir[dir];
+                
+                // reject invalid data
+                if (offmap(tmpx, tmpy))// || d_terrain[tmpy*d_width + tmpx] != Tile::GRASS)
+                    break;
+
+                // else move our region of interest by one tile
+                x = tmpx;
+                y = tmpy;
+                d_terrain[y*d_width + x] = t;
+                placed++;
+                switch (dir)
+                  {
+                    case 1: case 2: case 6: case 5:
+                      {
+                        for (i = 1; i <= thick ; i++)
+                          {
+                            if (offmap(x+i, y))
+                              continue;
+                            d_terrain[y*d_width + x+i] = t;
+                            placed++;
+                          }
+                      }
+                      break;
+                    case 7: case 3: case 0: case 4:
+                      {
+                        for (i = 1; i <= thick; i++)
+                          {
+                            if (offmap(x, y+i))
+                              continue;
+                            d_terrain[(y+i)*d_width + x] = t;
+                            placed++;
+                          }
+                      }
+                      break;
+                  }
+            }
+
+        }
+    }
+
+}
+
+bool MapGenerator::seekPlain(int& x, int& y)
+{
+    int orig_x = x;
+    int orig_y = y;
+    /* The algorithm here uses a large list of tiles to be checked.
+     * In the beginning, it is filled with the tiles surrounding the starting
+     * tile. Each tile is then checked if it contains grass. If not, all
+     * surrounding tiles are added to the list (we have to take some care to
+     * avoid infinite loops).
+     *
+     * Another way of describing it: The algorithm checks all tiles around the
+     * position for the existence of grass. It then checks the tiles in larger
+     * and larger circles around the position until it finds a grass tile.
+     */
+    if (d_terrain[y*d_width + x] == Tile::GRASS)
+        return true;
+
+    std::deque<Vector<int> > tiles;
+    
+    // fill the list with initial values; the rand is there to avoid a bias
+    // (i.e. prefer a certain direction)
+    for (int dir = rand() % 8, i = 0; i < 8; i++, dir = (dir+1)%8)
+        tiles.push_back(Vector<int>(x + d_xdir[dir], y + d_ydir[dir]));
+    
+    // now loop until all tiles were checked (should hardly happen)
+    while (!tiles.empty())
+    {
+        Vector<int> p = tiles.front();
+        tiles.pop_front();
+
+        if (offmap(p.x, p.y))
+            continue;
+        
+        // if we have found a patch of grass, we are lucky and return
+        if (d_terrain[p.y*d_width + p.x] == Tile::GRASS)
+        {
+            x = p.x;
+            y = p.y;
+            return true;
+        }
+        
+        // not found? Well, then append the surrounding tiles. To avoid double-
+        // checking (and therefore an infinite loop), only certain surrounding
+        // tiles are appended. See the following sketch:
+        //
+        //              ebbbe
+        //              b   b
+        //              b x b
+        //              b   b
+        //              ebbbe
+        //
+        // This is a circle of radius 2 around the position x. In the case of border
+        // tiles, only the tile directly outerwards is appended, the edge tiles 
+        // (which can be identified by distx == disty) append two new border and
+        // one new edge tile.
+        int dx = p.x - x;
+        int dy = p.y - y;
+        
+        // edge tile; append three new tiles
+        if (abs(dx) == abs(dy))
+        {
+            int newx = p.x - 1;
+            int newy = p.y - 1;
+
+            if (dx > 0)
+                newx = p.x + 1;
+            if (dy > 0)
+                newy = p.y + 1;
+            
+            tiles.push_back(Vector<int>(newx, newy));
+            tiles.push_back(Vector<int>(newx, p.y));
+            tiles.push_back(Vector<int>(p.x, newy));
+        }
+        else
+        {
+            if (abs(dx) > abs(dy) && dx > 0)        // right border
+                tiles.push_back(Vector<int>(p.x + 1, p.y));
+            else if (abs(dx) > abs(dy) && dx < 0)   //left border
+                tiles.push_back(Vector<int>(p.x - 1, p.y));
+            else if (abs(dx) < abs(dy) && dy > 0)   // top border
+                tiles.push_back(Vector<int>(p.x, p.y + 1));
+            else if (abs(dx) < abs(dy) && dy < 0)   // lower border
+                tiles.push_back(Vector<int>(p.x, p.y - 1));
+        }
+    }
+
+    // if this line is ever reached, we haven't found a free grass tile
+    // (should only happen under really exceptional circumstances)
+    x = orig_x;
+    y = orig_y;
+    return false;
+}
+
+bool MapGenerator::inhospitableTerrain(int x, int y, unsigned int width)
+{
+  for (unsigned int i = 0; i < width; i++)
+    for (unsigned int j = 0; j < width; j++)
+      if (d_terrain[(y+i)*d_width +(x+j)] == Tile::WATER ||
+         d_terrain[(y+i)*d_width +(x+j)] == Tile::MOUNTAIN)
+       return true;
+  return false;
+}
+
+void MapGenerator::makeCities(int cities)
+{
+
+    int city_count = 0;
+    int iterations = 0;
+    
+    // place the cities
+    while(city_count < cities)
+    {
+        int x = rand()%(d_width-2);
+        int y = rand()%(d_height-2);
+        if (inhospitableTerrain(x, y, cityset->getCityTileWidth()) && (iterations < 1000))
+        {
+            iterations++;
+            continue;
+        }
+        
+        // check if we can put the building
+        if (!canPutCity(x, y) && iterations < 1000)
+        {
+            iterations++;
+            continue;
+        }
+        
+        putCity(x, y, city_count);
+        iterations=0;
+    }
+    
+}
+
+bool MapGenerator::canPutCity(int x,int y)
+{
+  for (unsigned int i = 0; i < cityset->getCityTileWidth(); i++)
+    for (unsigned int j = 0; j < cityset->getCityTileWidth(); j++)
+      if (canPutBuilding(x+i,y+j) == false)
+        return false;
+        
+  return true;
+}
+
+void MapGenerator::putCity(int x, int y, int& city_count)
+{
+        d_building[y*d_width + x] = Maptile::CITY;
+
+        //cities shall only sit on grass tiles
+       for (unsigned int i = 0; i < cityset->getCityTileWidth(); i++)
+         for (unsigned int j = 0; j < cityset->getCityTileWidth(); j++)
+           d_terrain[(y+i)*d_width + (x+j)] = Tile::GRASS;
+        //cities cannot neighbor with mountain tiles
+        for (int Y = -1; Y <= (int)cityset->getCityTileWidth(); ++Y )
+            for (int X = -1; X <= (int)cityset->getCityTileWidth(); ++X)
+                if (d_terrain[(y+Y)*d_width + x+X] == Tile::MOUNTAIN)
+                    d_terrain[(y+Y)*d_width + x+X] = Tile::HILLS;
+
+        city_count++;
+}
+
+void MapGenerator::makeBuildings(Maptile::Building b, int building)
+{
+    int i, j, x, y;
+    int iterations = 10;
+    bool found_place = false;
+
+    unsigned int width = 1;
+
+    switch (b)
+      {
+      case Maptile::CITY:
+       width = cityset->getCityTileWidth(); break;
+      case Maptile::RUIN:
+       width = cityset->getRuinTileWidth(); break;
+      case Maptile::TEMPLE:
+       width = cityset->getTempleTileWidth(); break;
+      case Maptile::NONE:
+      case Maptile::SIGNPOST:
+      case Maptile::ROAD:
+      case Maptile::PORT:
+      case Maptile::BRIDGE:
+       width = 1;
+       break;
+      }
+
+   //If number of iterations is smaller 10, look for a suitable
+   //place. If this number is exceeded, place the temple on an
+   //island if neccessary.
+    for (i = 0; i < building; i++)
+    {        
+       for (j = 0; j < iterations; j++)
+       {
+             x = rand()%d_width;
+             y = rand()%d_height;
+        
+            found_place = true;
+            for (unsigned int k = 0; k < width; k++)
+              for (unsigned int l = 0; l < width; l++)
+                if (canPutBuilding(x+k, y+l) == false)
+                  found_place = false;
+
+            if (found_place == true)
+              break;
+       }
+
+       if (found_place == true)
+       {
+             d_terrain[y*d_width + x] = Tile::GRASS;
+             d_building[y*d_width + x] = b;
+            found_place = false;
+       }
+    }
+}
+
+/** 
+ * canPutBuilding
+ * Checks if we can put a building at the specified place. 
+ * If we are on a square with water, we cannot put it
+ * nor if it is too close.
+ * Checks for neighboring buildings yet sometimes these
+ * are bang next to each other - why?
+ * UL: Propably too many tries, then the algorithm forces the
+ * building to be placed.
+ */
+
+bool MapGenerator::canPutBuilding(int x,int y)
+{
+    // if the building is on water or mountains, return false
+    if (d_terrain[y*d_width +x] != Tile::GRASS )
+        return false;
+        
+    //if the building is close to the map boundaries, return false
+    if ((x < 3) || (x > (d_width-3)) || (y < 3) || (y > (d_height-3)))
+        return false;
+
+    int dist = (int)cityset->getCityTileWidth() + 1;
+    //if there is another building too close, return false
+    for (int locx = x-dist; locx <= x+dist; locx++)
+        for (int locy = y-dist; locy <= y+dist; locy++)
+        {
+            if (offmap(locx, locy))
+                continue;
+            if (d_building[locy*d_width + locx] != Maptile::NONE)
+                return false;
+        }  
+    // everything okay here! return true
+    return true;
+    
+}
+
+bool MapGenerator::tryToPlaceCity(int px,int py ,int& city_count)
+{
+    // first, try to place the city at the given location
+    if (canPutCity(px, py))
+    { 
+        putCity(px, py, city_count);
+        return true;
+    } 
+    
+    // else try all surrounding squares
+    for (int dir = 0; dir < 8; dir++)
+        if (canPutCity(px + d_xdir[dir], py + d_ydir[dir]))
+        {
+            putCity(px + d_xdir[dir], py + d_ydir[dir], city_count);
+            return true;
+        }
+
+    return false;                   
+}
+
+void MapGenerator::normalize()
+{
+    std::map<guint32,guint32> ajacentTer;
+    Tile::Type curTer=Tile::NONE, ajTer=Tile::NONE;
+
+    // that was 40 before. Now with rivers, the smaller the value - the more connected rivers we got.
+    int center_tiles = rand()%40;
+    //std::cerr << center_tiles << "\% chance of disconnecting rivers.\n";
+
+    // Go through every tile bar the outer edge
+    for(int globy = 1; globy < (d_height-2); globy++)
+        for(int globx = 1; globx < (d_width-2); globx++)
+        {
+            curTer = d_terrain[globy*d_width + globx];
+
+            // reset all counters
+            ajacentTer[Tile::GRASS] = 0;
+            ajacentTer[Tile::WATER] = 0;
+            ajacentTer[Tile::FOREST] = 0;
+            ajacentTer[Tile::HILLS] = 0;
+            ajacentTer[Tile::MOUNTAIN] = 0;
+            ajacentTer[Tile::SWAMP] = 0;
+
+            // count how many neighbours of each type we have
+            for(int locx = globx - 1; locx <= globx+1; locx++)
+                for(int locy = globy - 1; locy <= globy+1; locy++)
+                { 
+                     ajTer = d_terrain[locy*d_width +locx];
+                     ajacentTer[ajTer] += 1;
+                }
+
+            // we have counted our own tile as well
+            ajacentTer[curTer] -= 1;
+
+            if (curTer==Tile::WATER) // For the moment only water is normalized
+            {
+                if (ajacentTer[curTer]==0)
+                    d_terrain[globy*d_width +globx] = Tile::GRASS;
+                else if ((ajacentTer[curTer]==1) && (rand()%100 < 95 ))
+                    d_terrain[globy*d_width +globx] = Tile::GRASS;
+                else if ((ajacentTer[curTer]==2) && (rand()%100 < 70 ))
+                    d_terrain[globy*d_width +globx] = Tile::GRASS;
+                else if ((ajacentTer[curTer]==3) && (rand()%100 < center_tiles ))
+                    d_terrain[globy*d_width +globx] = Tile::GRASS;
+            }
+            else 
+            {
+                if (ajacentTer[Tile::WATER]==8)
+                    d_terrain[globy*d_width +globx] = Tile::WATER;
+                else if ((ajacentTer[Tile::WATER]==7) && (rand()%100 < 70 ))
+                    d_terrain[globy*d_width +globx] = Tile::WATER;
+                else if ((ajacentTer[Tile::WATER]==6) && (rand()%100 < 40 ))
+                    d_terrain[globy*d_width +globx] = Tile::WATER;
+             }
+        }
+}
+
+void MapGenerator::calculateBlockedAvenue(int x, int y)
+{
+  for (int i = x - 1; i <= x + 1; i++)
+    {
+      for (int j = y - 1; j <= y + 1; j++)
+       {
+         if (i < 0 || i >= d_width)
+           continue;
+         if (j < 0 || j >= d_height)
+           continue;
+         GameMap::getInstance()->calculateBlockedAvenue(i, j);
+       }
+    }
+}
+
+bool MapGenerator::placePort(int x, int y)
+{
+  //if (Citylist::getInstance()->getNearestCity(Vector<int>(x, y), 2) == NULL)
+    {
+      if (d_building[y*d_width + x] == 0)
+       {
+         Portlist *pl = Portlist::getInstance();
+         d_building[y*d_width + x] = Maptile::PORT;
+         pl->add(new Port(Vector<int>(x, y)));
+         calculateBlockedAvenue(x, y);
+         return true;
+       }
+    }
+  return false;
+}
+
+int MapGenerator::tryRoad(Vector<int> src, Vector<int>dest)
+{
+  return tryRoad (src.x, src.y, dest.x, dest.y);
+}
+
+int MapGenerator::tryRoad(int src_x, int src_y, int dest_x, int dest_y)
+{
+  Vector<int> src(src_x, src_y);
+  Vector<int> dest(dest_x, dest_y);
+
+  Path *p = new Path();
+  Stack s(NULL, src);
+
+  ArmyProto *basearmy = ArmyProto::createScout();
+  Army *a = Army::createNonUniqueArmy(*basearmy);
+  delete basearmy;
+  s.push_back(a);
+  // try to get there with a scout
+  guint32 moves = p->calculate(&s, dest, false);
+
+  delete p;
+  return (int)moves;
+}
+
+bool MapGenerator::makeRoad(Vector<int> src, Vector<int>dest)
+{
+  return makeRoad (src.x, src.y, dest.x, dest.y);
+}
+
+bool MapGenerator::makeRoad(int src_x, int src_y, int dest_x, int dest_y)
+{
+  bool retval = true;
+  GameMap *gm = GameMap::getInstance();
+  Vector<int> src(src_x, src_y);
+  Vector<int> dest(dest_x, dest_y);
+
+  RoadPathCalculator rpc(src);
+  Path *p = rpc.calculate(dest);
+
+  if (p->size() > 0)
+    {
+      Roadlist *rl = Roadlist::getInstance();
+      for (Path::iterator it = p->begin(); it != p->end(); it++)
+       {
+         int x = (*it).x;
+         int y = (*it).y;
+         if (gm->getTile(x, y)->getMaptileType() == Tile::WATER &&
+             gm->getTile(x, y)->getBuilding() != Maptile::BRIDGE)
+           {
+             retval = false;
+             break;
+           }
+         Citylist *cl = Citylist::getInstance();
+         if (cl->getObjectAt(x, y) == NULL)
+           {
+             if (d_building[y*d_width + x] == 0)
+               {
+                 d_building[y*d_width + x] = Maptile::ROAD;
+                 rl->add(new Road(Vector<int>(x, y)));
+                 calculateBlockedAvenue(x, y);
+               }
+           }
+       }
+
+    }
+  else
+    retval = false;
+  delete p;
+
+  return retval;
+}
+
+bool MapGenerator::isAccessible(Vector<int> src, Vector<int> dest)
+{
+  return isAccessible (src.x, src.y, dest.x, dest.y);
+}
+
+bool MapGenerator::isAccessible (int src_x, int src_y, int dest_x, int dest_y)
+{
+  bool retval = true;
+  Vector<int> src(src_x, src_y);
+  Vector<int> dest(dest_x, dest_y);
+
+  Path *p = new Path();
+  Stack s(NULL, src);
+
+  ArmyProto *basearmy = ArmyProto::createScout();
+  Army *a = Army::createNonUniqueArmy(*basearmy);
+  delete basearmy;
+  s.push_back(a);
+  // try to get there with a scout
+  if (p->calculate(&s, dest, true) <= 0)
+    retval = false;
+  delete p;
+
+  return retval;
+}
+
+bool MapGenerator::makeAccessible(Vector<int> src, Vector<int> dest)
+{
+  return makeAccessible(src.x, src.y, dest.x, dest.y);
+}
+
+bool MapGenerator::makeAccessible(int src_x, int src_y, int dest_x, int dest_y)
+{
+  bool retval = true;
+  GameMap *gm = GameMap::getInstance();
+  Vector<int> src(src_x, src_y);
+  Vector<int> dest(dest_x, dest_y);
+
+  Path *p = new Path();
+  Stack s(NULL, src);
+
+  ArmyProto *basearmy = ArmyProto::createScout();
+  Army *a = Army::createNonUniqueArmy(*basearmy);
+  delete basearmy;
+  s.push_back(a);
+  guint32 moves = p->calculate(&s, dest, false);
+
+  if (moves <= 0)
+    {
+      s.clear();
+      delete a;
+      ArmyProto *basearmy = ArmyProto::createBat();
+      a = Army::createNonUniqueArmy(*basearmy);
+      delete basearmy;
+      s.push_back(a);
+      moves = p->calculate(&s, dest, false);
+    }
+
+  if (moves != 0)
+    {
+      Path::iterator it = p->begin();
+      Path::iterator nextit = it;
+      nextit++;
+      for ( ; nextit != p->end(); it++, nextit++)
+       {
+         int x = (*it).x;
+         int y = (*it).y;
+         int nextx = (*nextit).x;
+         int nexty = (*nextit).y;
+         if (d_terrain[y*d_width + x] == Tile::MOUNTAIN)
+           {
+             d_terrain[y*d_width +x] = Tile::HILLS;
+             Maptile *t = new Maptile(gm->getTileset(), 
+                                      x, y, Tile::HILLS, NULL);
+             gm->setTile(x, y, t);
+             calculateBlockedAvenue(x, y);
+           }
+         if (d_terrain[y*d_width + x] == Tile::WATER &&
+             d_terrain[nexty*d_width + nextx] != Tile::WATER)
+           {
+             if (placePort(x, y) == true)
+               {
+                 if (isAccessible(src_x, src_y, dest.x, dest.y))
+                   {
+                     retval = true;
+                     break;
+                   }
+               }
+           }
+         else if (d_terrain[y*d_width + x] != Tile::WATER &&
+                  d_terrain[nexty*d_width + nextx] == Tile::WATER)
+           {
+             if (placePort(nextx, nexty) == true)
+               {
+                 if (isAccessible(src_x, src_y, dest.x, dest.y))
+                   {
+                     retval = true;
+                     break;
+                   }
+               }
+           }
+
+       }
+    }
+  else
+    retval = false;
+
+  delete p;
+  return retval;
+}
+
+std::vector<pair<int , Vector<int> > > MapGenerator::findBridgePlaces()
+{
+    std::vector<pair<int , Vector<int> > > result;
+    result.clear();
+
+    for(int j = 1; j < d_height-5; j++)
+        for(int i = 1; i < d_width-5; i++)
+        {
+            if (
+                d_terrain[(j  )*d_width + i+1] != Tile::WATER &&
+                d_terrain[(j+1)*d_width + i+1] == Tile::WATER &&
+                d_terrain[(j+2)*d_width + i+1] == Tile::WATER &&
+                d_terrain[(j+3)*d_width + i+1] != Tile::WATER &&
+                d_terrain[(j+1)*d_width + i  ] == Tile::WATER &&
+                d_terrain[(j+2)*d_width + i  ] == Tile::WATER &&
+                d_terrain[(j+1)*d_width + i+2] == Tile::WATER &&
+                d_terrain[(j+2)*d_width + i+2] == Tile::WATER
+                )
+            {
+                int count_left =
+                (int)(d_terrain[(j  )*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j+1)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j  )*d_width + i-1] == Tile::WATER) +
+                (int)(d_terrain[(j+1)*d_width + i-1] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i-1] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i-1] == Tile::WATER);
+                int count_right =
+                (int)(d_terrain[(j  )*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j+1)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j  )*d_width + i+3] == Tile::WATER) +
+                (int)(d_terrain[(j+1)*d_width + i+3] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i+3] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i+3] == Tile::WATER);
+                
+                if(count_left > 5 && count_right > 5)
+                    result.push_back(std::make_pair(1, Vector<int>(i,j) ));
+            }
+            if (
+                d_terrain[(j+1)*d_width + i  ] != Tile::WATER &&
+                d_terrain[(j+1)*d_width + i+1] == Tile::WATER &&
+                d_terrain[(j+1)*d_width + i+2] == Tile::WATER &&
+                d_terrain[(j+1)*d_width + i+3] != Tile::WATER &&
+                d_terrain[(j  )*d_width + i+1] == Tile::WATER &&
+                d_terrain[(j  )*d_width + i+2] == Tile::WATER &&
+                d_terrain[(j+2)*d_width + i+1] == Tile::WATER &&
+                d_terrain[(j+2)*d_width + i+2] == Tile::WATER
+                )
+            {
+                int count_top =
+                (int)(d_terrain[(j  )*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j  )*d_width + i+1] == Tile::WATER) +
+                (int)(d_terrain[(j  )*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j  )*d_width + i+3] == Tile::WATER) +
+                (int)(d_terrain[(j-1)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j-1)*d_width + i+1] == Tile::WATER) +
+                (int)(d_terrain[(j-1)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j-1)*d_width + i+3] == Tile::WATER);
+
+                int count_bottom =
+                (int)(d_terrain[(j+2)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i+1] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j+2)*d_width + i+3] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i  ] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i+1] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i+2] == Tile::WATER) +
+                (int)(d_terrain[(j+3)*d_width + i+3] == Tile::WATER);
+
+                if(count_top > 5 && count_bottom > 5)
+                    result.push_back(std::make_pair(2, Vector<int>(i,j) ));
+            }
+        }
+    // randomize
+    std::random_shuffle(result.begin(),result.end());
+
+    // remove those that are too close to each other
+    std::set<int> bad;bad.clear();
+    for(size_t r = 0; r<result.size() ; ++r)
+        for(size_t s = r+1; s<result.size() ; ++s)
+            if(dist(Vector<float>(result[r].second),Vector<float>(result[s].second)) < 4.5)
+                bad.insert(r);
+    std::vector<pair<int , Vector<int> > > filter;filter.clear();
+    for(size_t r = 0; r<result.size() ; ++r)
+        if(bad.find(r) == bad.end())
+            filter.push_back(result[r]);
+    result=filter;
+
+    return result;
+}
+
+void MapGenerator::makeRoads()
+{
+  GameMap::deleteInstance();
+  Citylist::deleteInstance();
+  Roadlist::deleteInstance();
+  Portlist::deleteInstance();
+
+  GameMap::setWidth(d_width);
+  GameMap::setHeight(d_height);
+  GameMap::getInstance("default", "default", cityset->getSubDir())->fill(this);
+  Roadlist::getInstance();
+  //the game map class smooths the map, so let's take what it smoothed.
+  for (int y = 0; y < d_height; y++)
+    for (int x = 0; x < d_width; x++)
+      d_terrain[y*d_width + x] = 
+       GameMap::getInstance()->getTile(x, y)->getMaptileType();
+
+  for (int y = 0; y < d_height; y++)
+    for (int x = 0; x < d_width; x++)
+      {
+       if (d_building[y*d_width + x] == Maptile::CITY)
+         Citylist::getInstance()->add
+           (new City(Vector<int>(x,y), cityset->getCityTileWidth()));
+      }
+  GameMap::getInstance()->calculateBlockedAvenues();
+
+  Citylist *cl = Citylist::getInstance();
+  for (Citylist::iterator it = cl->begin(); it != cl->end(); it++)
+    {
+      if (rand() % 2 == 0)
+       continue;
+      City *c = cl->getNearestCityPast((*it)->getPos(), 13);
+      Vector<int> dest = c->getPos();
+      Vector<int> src = (*it)->getPos();
+      //does it already have a road going to it?
+      if (Roadlist::getInstance()->getNearestObjectBefore(dest, 
+                                                         c->getSize() + 1))
+       continue;
+
+      makeRoad(src, dest);
+      progress.emit(.810, _("paving roads..."));
+    }
+  
+  //make all cities accessible by allowing movement to a central city
+  Vector<int> pos = GameMap::getCenterOfMap();
+  City *center = cl->getNearestCity(pos);
+  for (Citylist::iterator it = cl->begin(); it != cl->end(); it++)
+    {
+      if (center == *it)
+       continue;
+      if (isAccessible(center->getPos(), (*it)->getPos()) == false)
+       {
+       makeAccessible(center->getPos(), (*it)->getPos());
+       }
+      progress.emit(.810, _("paving roads..."));
+    }
+
+  Roadlist::deleteInstance();
+  GameMap::deleteInstance();
+  Citylist::deleteInstance();
+  Portlist::deleteInstance();
+}
+
+void MapGenerator::rescueLoneTiles(Tile::Type FIND_THIS, Tile::Type REPLACE, bool grow)
+{
+    int box[3][3];
+    memset (box, 0, sizeof (box));
+
+    if(grow)
+    {
+        for(int j = 1; j < d_height-1; j++)
+            for(int i = 1; i < d_width-1; i++)
+            {
+                if (d_terrain[j*d_width + i] == FIND_THIS &&
+                   (d_terrain[(j-1)*d_width + i-1] == FIND_THIS &&
+                    d_terrain[(j  )*d_width + i-1] == FIND_THIS &&
+                    d_terrain[(j-1)*d_width + i  ] != FIND_THIS))
+                    d_terrain[(j-1)*d_width + i  ] =  FIND_THIS;
+            }
+    }
+
+    for(int iteration=0; iteration <8 ;++iteration)
+    {
+        for(int j = 0; j < d_height; j++)
+            for(int i = 0; i < d_width; i++)
+            {
+                if(d_terrain[j*d_width + i] == FIND_THIS)
+                { 
+                    for (int I = -1; I <= +1; ++I)
+                        for (int J = -1; J <= +1; ++J)
+                            if (!(offmap(i+I,j+J)))
+                                box[J+1][I+1] = (d_terrain[(j+J)*d_width + (i+I)] == d_terrain[j*d_width + i]);
+                            else
+                                box[J+1][I+1] = 0;
+
+                    if (!box[0][2] && !box[1][2] && /***********/ 
+                        /***********/  box[1][1] &&  box[2][1] && 
+                        !box[0][0] && !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && !box[2][2] && 
+                         box[0][1] &&  box[1][1] && /***********/
+                        /***********/ !box[1][0] && !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (!box[0][2] && /***********/ !box[2][2] && 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/  box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/  box[1][2] && /***********/
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        !box[0][0] && /***********/ !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+
+                    if (/***********/ !box[1][2] && /***********/ 
+                        /***********/  box[1][1] &&  box[2][1] && 
+                        !box[0][0] && !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && /***********/ 
+                         box[0][1] &&  box[1][1] && /***********/
+                        /***********/ !box[1][0] && !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ /***********/ !box[2][2] && 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/  box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/  box[1][2] && /***********/
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/ /***********/ !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+
+                    if (!box[0][2] && !box[1][2] && /***********/ 
+                        /***********/  box[1][1] &&  box[2][1] && 
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && !box[2][2] && 
+                         box[0][1] &&  box[1][1] && /***********/
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (!box[0][2] && /***********/ /***********/ 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/  box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/  box[1][2] && /***********/
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        !box[0][0]    /***********/ /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+
+                    if (/***********/ !box[1][2] && /***********/ 
+                        !box[0][1] &&  box[1][1] &&  box[2][1] && 
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && /***********/ 
+                         box[0][1] &&  box[1][1] && !box[2][1] &&
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && /***********/ 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/  box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/  box[1][2] && /***********/
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+
+                    if ( box[0][2] && !box[1][2] && /***********/
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] &&  box[2][2] && 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/ !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && /***********/ 
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                         box[0][0] && !box[1][0]    /***********/)
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (/***********/ !box[1][2] && /***********/  
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                        /***********/ !box[1][0] &&  box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+
+
+                    if ( box[0][2] && !box[1][2] &&  box[2][2] &&  
+                         box[0][1] &&  box[1][1] &&  box[2][1] && 
+                         box[0][0] && !box[1][0] &&  box[2][0])
+                            d_terrain[j*d_width + i+(rand()%2?+1:-1)] = FIND_THIS;
+                    if ( box[0][2] &&  box[1][2] &&  box[2][2] &&  
+                        !box[0][1] &&  box[1][1] && !box[2][1] && 
+                         box[0][0] &&  box[1][0] &&  box[2][0])
+                            d_terrain[(j+(rand()%2?+1:-1))*d_width + i] = FIND_THIS;
+
+                    if ( box[0][2] && !box[1][2] && !box[2][2] &&  
+                         box[0][1] &&  box[1][1] && !box[2][1] && 
+                        !box[0][0] &&  box[1][0] &&  box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (!box[0][2] && !box[1][2] &&  box[2][2] &&  
+                        !box[0][1] &&  box[1][1] &&  box[2][1] && 
+                         box[0][0] &&  box[1][0] && !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if ( box[0][2] &&  box[1][2] && !box[2][2] &&  
+                        !box[0][1] &&  box[1][1] &&  box[2][1] && 
+                        !box[0][0] && !box[1][0] &&  box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                    if (!box[0][2] &&  box[1][2] &&  box[2][2] &&  
+                         box[0][1] &&  box[1][1] && !box[2][1] && 
+                         box[0][0] && !box[1][0] && !box[2][0])
+                            d_terrain[j*d_width + i] = REPLACE;
+                }
+            }
+    }
+}
+
+void MapGenerator::surroundMountains(int minx, int maxx, int miny, int maxy)
+{
+  for(int j = miny; j < maxy; j++)
+    for(int i = minx; i < maxx; i++)
+      if(d_terrain[j*d_width + i] == Tile::MOUNTAIN)
+       for(int J = -1; J <= +1; ++J)
+         for(int I = -1; I <= +1; ++I)
+           if((!(offmap(i+I,j+J))) &&
+              (d_terrain[(j+J)*d_width + (i+I)] != Tile::MOUNTAIN))
+             {
+               if(d_terrain[(j+J)*d_width + (i+I)] != Tile::WATER)
+                 d_terrain[(j+J)*d_width + (i+I)] = Tile::HILLS;
+               else 
+                 // water has priority here, there was some work done to conenct bodies of water
+                 // so don't break those connections.
+                 d_terrain[(j  )*d_width + (i  )] = Tile::HILLS;
+             }
+}