void GameLoaderC3Map::Impl::loadCity(std::fstream& f, CityPtr oCity)
{
  Tilemap& oTilemap = oCity->getTilemap();

  /* get number of city */

  f.seekg(kLocation, std::ios::beg);
  unsigned int location=0;
  f.read((char*)&location, 1);
  StringHelper::debug( 0xff, "Location of city is %d", (int)(location+1) );

  std::string cityName = "";
  switch( location+1 ) {
    case 1: case 29: cityName = "Lugdunum"; break;
    case 2: cityName = "Corinthus"; break;
    case 3: case 37: cityName = "Londinium"; break;
    case 4: case 13: case 28: cityName = "Mediolanum"; break;
    case 5: case 40: cityName = "Lindum"; break;
    case 6: cityName = "Toletum"; break;
    case 7: case 33: cityName = "Valentia"; break;
    case 8: case 35: cityName = "Caesarea"; break;
    case 9: case 30: cityName = "Carthago"; break;
    case 10: cityName = "Cyrene"; break;
    case 11: case 15: case 25: cityName = "Tarraco"; break;
    case 12: cityName = "Hierosolyma"; break;
    case 14: case 26: cityName = "Syracusae"; break;
    case 16: case 31: cityName = "Tarsus"; break;
    case 17: case 32: cityName = "Tingis"; break;
    case 18: cityName = "Augusta Trevorum"; break;
    case 19: cityName = "Carthago Nova"; break;
    case 20: cityName = "Leptis Magna"; break;
    case 21: cityName = "Athenae"; break;
    case 22: cityName = "Brundisium"; break;
    case 23: cityName = "Capua"; break;
    case 24: cityName = "Tarentum"; break;
    case 27: cityName = "Miletus"; break;
    case 34: cityName = "Lutetia"; break;
    case 36: cityName = "Sarmizegetusa"; break;
    case 38: cityName = "Damascus"; break;
    case 39: cityName = "Massilia"; break;
  }

  oCity->setName( cityName );

  f.seekg(kSize, std::ios::beg);

  int size;  // 32bits
  int size_2;
  f.read((char*)&size,   4);
  f.read((char*)&size_2, 4);
  StringHelper::debug( 0xff, "Map size is %d", size );

  if (size != size_2)
  {
    THROW("Horisontal and vertical map sizes are different!");
  }

  oTilemap.resize(size);

  // need to rewrite better
  ScopedPtr<short> pGraphicGrid( new short[26244] );
  ScopedPtr<unsigned char> pEdgeGrid( new unsigned char[26244] );
  ScopedPtr<short> pTerrainGrid( new short[26244] );
  ScopedPtr<unsigned char> pRndmTerGrid( new unsigned char[26244] );
  ScopedPtr<unsigned char> pRandomGrid( new unsigned char[26244] );
  ScopedPtr<unsigned char> pZeroGrid( new unsigned char[26244] );
  
  if( pGraphicGrid.isNull() || pEdgeGrid.isNull() || pTerrainGrid.isNull() ||
      pRndmTerGrid.isNull() || pRandomGrid.isNull() || pZeroGrid.isNull() )
  {
    THROW("NOT ENOUGH MEMORY!!!! FATAL");
  }  
  
  // here also make copy of original arrays in memory

  f.seekg(kGraphicGrid, std::ios::beg);
  f.read((char*)pGraphicGrid.data(), 52488);
  f.seekg(kEdgeGrid, std::ios::beg);
  f.read((char*)pEdgeGrid.data(), 26244);
  f.seekg(kTerrainGrid, std::ios::beg);
  f.read((char*)pTerrainGrid.data(), 52488);
  f.seekg(kRndmTerGrid, std::ios::beg);
  f.read((char*)pRndmTerGrid.data(), 26244);
  f.seekg(kRandomGrid, std::ios::beg);
  f.read((char*)pRandomGrid.data(), 26244);
  f.seekg(kZeroGrid, std::ios::beg);
  f.read((char*)pZeroGrid.data(), 26244);

  std::map< int, std::map< int, unsigned char > > edgeData;

  // loads the graphics map
  int border_size = (162 - size) / 2;

  for (int itA = 0; itA < size; ++itA)
  {
    for (int itB = 0; itB < size; ++itB)
    {
      int i = itB;
      int j = size - itA - 1;

      int index = 162 * (border_size + itA) + border_size + itB;  

      Tile& tile = oTilemap.at(i, j);
      tile.setPicture( TileHelper::convId2PicName( pGraphicGrid.data()[index] ) );
      tile.setOriginalImgId( pGraphicGrid.data()[index] );

      edgeData[ i ][ j ] =  pEdgeGrid.data()[index];
      TileHelper::decode( tile, pTerrainGrid.data()[index] );
    }    
  }

  for (int i = 0; i < size; ++i)
  {
    for (int j = 0; j < size; ++j)
    {
      unsigned char ed = edgeData[ i ][ j ];
      if( ed == 0x00)
      {
        int size = 1;

	      {
	        int dj;
	        try
	        {	
	          // find size, 5 is maximal size for building
	          for (dj = 0; dj < 5; ++dj)
	          {
							int edd = edgeData[ i ][ j - dj ];
	            // find bottom left corner
							if (edd == 8 * dj + 0x40)
	            {
	              size = dj + 1;
	              break;
	            }
	          }
	        }
	        catch(...)
	        {
	          size = dj + 1;
	        }
	      }
	
        StringHelper::debug( 0xff, "Multi-tile x %d at (%d,%d)", size, i, j );
	      	
	      Tile& master = oTilemap.at(i, j - size + 1);
      	
        StringHelper::debug( 0xff, "Master will be at (%d,%d)", master.getI(), master.getJ() );
      	
	      for (int di = 0; di < size; ++di)
        {
	        for (int dj = 0; dj < size; ++dj)
	        {
	            oTilemap.at(master.getI() + di, master.getJ() + dj).setMasterTile(&master);
	        }
        }
    	
        StringHelper::debug( 0xff, " decoding " );
      }
      
      // Check if it is building and type of building
      //if (ttile.getMasterTile() == NULL)
      decodeTerrain( oTilemap.at( i, j ), oCity );
    }
  }
}
void C3Map::Impl::loadCity(std::fstream& f, PlayerCityPtr oCity)
{
  Tilemap& oTilemap = oCity->tilemap();

  /* get number of city */

  f.seekg(kLocation, std::ios::beg);
  unsigned int location=0;
  f.read((char*)&location, 1);
  Logger::warning( "C3MapLoader: location of city is %d", (int)(location) );

  std::string cityName = LoaderHelper::getDefaultCityName( location );
  oCity->setName( cityName );

  f.seekg(kSize, std::ios::beg);

  int map_size;  // 32bits
  int size_2;
  f.read((char*)&map_size,   4);
  f.read((char*)&size_2, 4);
  Logger::warning( "C3MapLoader: map size is %d", map_size );

  if (map_size != size_2)
  {
    THROW("Horizontal and vertical map sizes are different!");
  }

  oCity->resize(map_size);

  // need to rewrite better
  ScopedArrayPtr<short> pGraphicGrid( new short[tilemap::c3mapSizeSq] );
  ScopedArrayPtr<unsigned char> pEdgeGrid( new unsigned char[tilemap::c3mapSizeSq] );
  ScopedArrayPtr<short> pTerrainGrid( new short[tilemap::c3mapSizeSq] );
  ScopedArrayPtr<unsigned char> pRndmTerGrid( new unsigned char[tilemap::c3mapSizeSq] );
  ScopedArrayPtr<unsigned char> pRandomGrid( new unsigned char[tilemap::c3mapSizeSq] );
  ScopedArrayPtr<unsigned char> pElevationGrid( new unsigned char[tilemap::c3mapSizeSq] );

  if( pGraphicGrid.isNull() || pEdgeGrid.isNull() || pTerrainGrid.isNull() ||
      pRndmTerGrid.isNull() || pRandomGrid.isNull() || pElevationGrid.isNull() )
  {
    THROW("NOT ENOUGH MEMORY!!!! FATAL");
  }

  // here also make copy of original arrays in memory

  f.seekg(kGraphicGrid, std::ios::beg);
  f.read((char*)pGraphicGrid.data(), tilemap::c3mapSizeSq*2);
  f.seekg(kEdgeGrid, std::ios::beg);
  f.read((char*)pEdgeGrid.data(), tilemap::c3mapSizeSq);
  f.seekg(kTerrainGrid, std::ios::beg);
  f.read((char*)pTerrainGrid.data(), tilemap::c3mapSizeSq*2);
  f.seekg(kRndmTerGrid, std::ios::beg);
  f.read((char*)pRndmTerGrid.data(), tilemap::c3mapSizeSq);
  f.seekg(kRandomGrid, std::ios::beg);
  f.read((char*)pRandomGrid.data(), tilemap::c3mapSizeSq);
  f.seekg(kElevationGrid, std::ios::beg);
  f.read((char*)pElevationGrid.data(), tilemap::c3mapSizeSq);

  std::map< int, std::map< int, unsigned char > > edgeData;

  // loads the graphics map
  int border_size = (gfx::tilemap::c3mapSize - map_size) / 2;

  for (int itA = 0; itA < map_size; ++itA)
  {
    for (int itB = 0; itB < map_size; ++itB)
    {
      int i = itB;
      int j = map_size - itA - 1;

      int index = gfx::tilemap::c3mapSize * (border_size + itA) + border_size + itB;

      Tile& tile = oTilemap.at(i, j);
      tile.setPicture( imgid::toResource( pGraphicGrid.data()[index] ) );
      tile.setOriginalImgId( pGraphicGrid.data()[index] );
      //tile.setHeight( pElevationGrid.data()[ index ] );

      edgeData[ i ][ j ] =  pEdgeGrid.data()[index];
      tile::decode( tile, pTerrainGrid.data()[index] );
      tile::fixPlateauFlags( tile );
    }
  }

  for (int i = 0; i < map_size; ++i)
  {
    for (int j = 0; j < map_size; ++j)
    {
      unsigned char ed = edgeData[ i ][ j ];
      if( ed == 0x00)
      {
        int size = 1;

        {
          int dj;
          try
          {
            // find size, 5 is maximal size for building
            for (dj = 0; dj < gfx::tilemap::c3bldSize; ++dj)
            {
              int edd = edgeData[ i ][ j - dj ];
              // find bottom left corner
              if (edd == 8 * dj + 0x40)
              {
                size = dj + 1;
                break;
              }
            }
          }
          catch(...)
          {
            size = dj + 1;
          }
        }

        Tile& master = oTilemap.at(i, j - size + 1);
        for (int di = 0; di < size; ++di)
        {
          for (int dj = 0; dj < size; ++dj)
          {
            oTilemap.at(master.pos() + TilePos( di, dj ) ).setMasterTile(&master);
          }
        }
      }

      // Check if it is building and type of building
      //if (ttile.getMasterTile() == NULL)
      LoaderHelper::decodeTerrain( oTilemap.at( i, j ), oCity );
    }
  }
}