This patch uses Mark Isaak's plate tectonic simulator to make freeciv
maps.  This needs to be applied after applying Josh Cogliati's patch
which adds a sixth map generator to freeciv.

To use this patch, set the generator to 7 (which will generate pure
tectonic shift maps) or 8 (which will generate hybrid maps: Maps
which are tectonically generated maps with filtered noise added so that
the oceans have more islands to explore).  

Note that this code takes far longer to generate maps than the other
generators; on the other hand, the lands generated are far more realistic,
especially for larger maps.

- Sam 

--- freeciv-1.14.0/common/map.h.orig	Sat Mar 22 17:25:36 2003
+++ freeciv-1.14.0/common/map.h	Sat Mar 22 17:42:07 2003
@@ -619,7 +619,7 @@
 
 #define MAP_DEFAULT_GENERATOR    1
 #define MAP_MIN_GENERATOR        1
-#define MAP_MAX_GENERATOR        6
+#define MAP_MAX_GENERATOR        8
 
 #define MAP_DEFAULT_TINYISLES    FALSE
 #define MAP_MIN_TINYISLES        FALSE
--- freeciv-1.14.0/server/mapgen.c.orig	Sat Mar 22 17:25:49 2003
+++ freeciv-1.14.0/server/mapgen.c	Sat Mar 22 18:01:44 2003
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <math.h> /* For the plate tectonic simulator */
 
 #include "fcintl.h"
 #include "game.h"
@@ -42,6 +43,7 @@
 static void mapgenerator4(void);
 static void mapgenerator5(void);
 static void mapgenerator6(void);
+static void mapgenerator_tectonic(void);
 static void smooth_map(void);
 static void adjust_map(int minval);
 
@@ -824,7 +826,7 @@
   1) with map.landpercent it generates a ocean/grassland map 
   2) it then calls the above functions to generate the different terrains
 **************************************************************************/
-static void make_land(void)
+static void make_land(int window_size)
 {
   int tres=(maxval*map.landpercent)/100;
   int count=0;
@@ -847,7 +849,7 @@
     else
       tres*=9;
     tres/=10;
-  } while (abs(total-count)> maxval/40);
+  } while (abs(total-count)> window_size/40);
   if (map.separatepoles) {
     make_passable();
   }
@@ -1199,6 +1201,8 @@
     /* with a lower number to try again */
     if (map.generator == 6 )
       mapgenerator6();
+    if (map.generator == 7 || map.generator == 8)
+      mapgenerator_tectonic();
     if (map.generator == 5 )
       mapgenerator5();
     if (map.generator == 4 )
@@ -1248,7 +1252,7 @@
   /*!PS: I don't have the time to have several test runs */
   /* to find a mapping from percents to generator 1 settings. */
 
-  if(map.generator==1){
+  if(map.generator==1 || map.generator==7){
     /*map.riverlength*= 10; */
     /*I leave this out, people will get too upset 
       if they have to change all their scripts */
@@ -1292,7 +1296,7 @@
 
 /**************************************************************************
   since the generated map will always have a positive number as minimum height
-  i reduce the height so the lowest height is zero, this makes calculations
+  reduce the height so the lowest height is zero, this makes calculations
   easier
 **************************************************************************/
 static void adjust_map(int minval)
@@ -1341,7 +1345,829 @@
   maxval-=minval;
   adjust_map(minval);
 
-  make_land();
+  make_land(maxval);
+  free(height_map);
+  height_map = NULL;
+}
+
+/**************************************************************************
+ The following code was written by Mark Isaak in 1988 and converted in to
+ a freeciv-compatible form 2003 by Sam Trenholme
+ *************************************************************************/
+
+/*
+ * A program to simulate tectonics.
+ *
+ * Copyright 1988 by Mark Isaak.
+ * Copyright 2003 Sam Trenholme; with Mark Isaak's permission, I have
+ * relicensed this under the GPL.
+ *
+ * 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 2, 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.
+ *
+ *
+ * Wish list (from 1988):
+ *      Do it on a sphere, not a square torus (not wanted for FreeCiv)
+ *	Give plates angular momentum
+ *	Make some constants variable
+ *	Horsts and grabens
+ *	Let 2 plates fuse together and/or 1 plate split apart sometimes
+ *	Astroblemes
+ *	Take density of rock into account
+ */
+
+/*
+ * ---------- Structures -----------------------------------------------------
+ */
+
+/*
+ * ---------- Defined parameters ---------------------------------------------
+ *
+ * Some notes on Earth for comparison:
+ *   Mean elevation of land = 840 m.
+ *   Kilamanjaro = 5895 m.
+ *   Everest = 8848 m.
+ *   Dead Sea = -400 m.
+ *   Gread Rift Valley = -150 m.
+ *   Andes = 6950 m.
+ *   Marianas Trench = -11000 m.
+ *   Mean depth of sea = -3810 m.
+ */
+
+struct tectonic_data {
+
+  int   xsize; /* Size of map along x axis */
+  int   ysize; /* Size of map along y axis */
+  int   nplates;	/* # of plates in world at genesis */
+  int   maxplates;	/* maximum # of plates we can have */
+  int   ncontinents;	/* # of plates which are continental */
+  int   nhotspots;	/* # of hot spots */
+
+  int   landelev;	/* starting elevation of land */
+  int   oceanelev;	/* starting elevation of oceans */
+
+  int   epochmove;	/* max movement during one epoch */
+
+  float foldfactor;	/* how much to increase ht. of folds */
+  int   riftelev;	/* elevation for rifts */
+  int   subsumeheight; 	/* elevation change for coastal ranges */
+  int   trenchheight;	/* elev. change for trench by coastal range */
+  int   hotspotheight; 	/* average ht. growth of hot spots */
+
+  int   riftminerals; 	/* minerals in rifts */
+  int   subsumeminerals; 	/* minerals in costal ranges */
+  int   archipminerals; 	/* minerals in archipelagos */
+  int   hotspotminerals; 	/* minerals in underwater hot spots */
+ 
+  float erodefactor; 	/* how much of a height to erode */
+  float submergefactor; 	/* how being underwater slows erosion */
+  int   skyelev;		/* no erosion above this */
+  int   waveaction; 	/* erosion due entirely to waves */
+  int   subsidefactor; 	/* how fast ocean floor sinks */
+  int   basinelev; 	/* how far ocean floor can sink */
+
+};
+
+static struct tectonic_data tectonic;
+
+void init_tec_data() {
+  tectonic.xsize = map.xsize; /* Width of map */
+  tectonic.ysize = map.ysize; /* Height of map */
+
+  tectonic.nplates = 20; /* # of plates in world at genesis */
+  tectonic.maxplates = 27; /* maximum # of plates we can have */
+  tectonic.ncontinents = 5; /* # of plates which are continental */
+  tectonic.nhotspots = 10; /* # of hot spots */
+
+  tectonic.landelev = 800; /* starting elevation of land */
+  tectonic.oceanelev = -1000; /* starting elevation of oceans */
+
+  tectonic.epochmove = 5; /* max movement during one epoch */
+
+  tectonic.foldfactor = 1.2; /* how much to increase ht. of folds */
+  tectonic.riftelev = -400; /* elevation for rifts */
+  tectonic.subsumeheight = 1200; /* elevation change for coastal ranges */
+  tectonic.trenchheight = -500; /* elev. change for trench by coastal range */
+  tectonic.hotspotheight = 600; /* average ht. growth of hot spots */
+
+  tectonic.riftminerals = 7; /* minerals in rifts */
+  tectonic.subsumeminerals = 3; /* minerals in costal ranges */
+  tectonic.archipminerals = 5; /* minerals in archipelagos */
+  tectonic.hotspotminerals = 2; /* minerals in underwater hot spots */
+
+  tectonic.erodefactor = 0.023; /* how much of a height to erode */
+  tectonic.submergefactor = 0.2; /* how being underwater slows erosion */
+  tectonic.skyelev = 10000; /* no erosion above this */
+  tectonic.waveaction = 400; /* erosion due entirely to waves */
+  tectonic.subsidefactor = 0.05; /* how fast ocean floor sinks */
+  tectonic.basinelev = -9000; /* how far ocean floor can sink */
+  }
+
+/*
+ * Tectonic plate
+ */
+typedef struct {
+    float	xvec, yvec;	/* direction of plate movement */
+    short	dx, dy;		/* how far do move plate per age */
+    bool	continent;	/* whether initially continent or ocean */
+} Plate_t;
+
+/*
+ * Hot spot
+ */
+typedef struct {
+    short	x, y;		/* location of hot spot */
+    short	howhot;		/* how much it spews forth */
+} Hotspot_t;
+
+/*
+ * A piece of land which moves around
+ */
+typedef struct rock_s {
+    short	elev;		/* elevation */
+    short	elevchange;	/* change in elevation due to erosion */
+    Plate_t	*plate;		/* which plate it belongs to */
+    bool	moved;		/* whether we've moved this iteration */
+    long	minerals;	/* how many minerals */
+    struct rock_s *next;	/* next in linked list */
+} Rock_t;
+
+/*
+ * ---------- Global variables -----------------------------------------------
+ */
+Rock_t	*surface[1024][1024];	/* surface of planet */
+Plate_t	plates[1024];		/* descriptions of plates */
+Hotspot_t	hotspots[1024];	/* descriptions of hot spots */
+
+int	nplates;			/* # of tectonic plates */
+Rock_t	*freeRockList;			/* ptr to list of unused rocks */
+short	maxelev, minelev;		/* elevation extremes */
+
+/*
+ * ---------- Utilities ------------------------------------------------------
+ */
+/*
+ * Return a random number from 0 to n-1.
+ */
+  int
+Rnd(n)
+  int n;
+{
+    return myrand(n); /* Freeciv's RNG */
+}
+
+/*
+ * Wraparound from one side of the world to the other.
+ */
+  int
+Wrap_x(val)
+  register int val;	/* x coordinate */
+{
+    if (val < 0)
+        val += tectonic.xsize;
+    else if (val >= tectonic.xsize)
+        val -= tectonic.xsize;
+    return (val);
+}
+
+  int
+Wrap_y(val)
+  register int val;	/* y coordinate */
+{
+    if (val < 0)
+        val += tectonic.ysize;
+    else if (val >= tectonic.ysize)
+        val -= tectonic.ysize;
+    return (val);
+}
+
+/*
+ * Allocate a rock.
+ */
+  Rock_t *
+AllocRock(pl)
+  Plate_t	*pl;	/* which plate it goes on */
+{
+    Rock_t	*rp;	/* ptr to rock */
+
+    if (freeRockList) {
+        rp = freeRockList;
+        freeRockList = rp->next;
+    } else
+        rp = (Rock_t *)malloc(sizeof(Rock_t));
+    rp->plate = pl;
+    rp->elev = (pl->continent ? tectonic.landelev : tectonic.oceanelev);
+    rp->elevchange = 0;
+    rp->moved = FALSE;
+    rp->minerals = 0;
+    rp->next = NULL;
+    return (rp);
+}
+
+/*
+ * ---------- Initialization -------------------------------------------------
+ */
+
+/*
+ * Put plates at random spots on the planet.
+ * Make tectonic.ncontinents of them land, the rest ocean.
+ */
+int SeedPlates()
+{
+    register int i;
+    register Plate_t *pl;	/* ptr to plates */
+
+    pl = &plates[0];
+    for (i = 0; i < tectonic.nplates; ++i, ++pl) {
+        pl->dx = Rnd(tectonic.xsize);
+        pl->dy = Rnd(tectonic.ysize);
+        /*
+         * Check if this spot is already taken.
+         */
+        if (surface[pl->dx][pl->dy]) {
+            --pl;
+            --i;
+            continue;	/* try again */
+        }
+        surface[pl->dx][pl->dy] = (Rock_t *)pl;
+        pl->xvec = 0.0;
+        pl->yvec = 0.0;
+        pl->continent = (i < tectonic.ncontinents);
+    }
+    return 0;
+}
+
+/*
+ * Initialize the surface.  Allocate a rock for each spot on the surface
+ * and assign it to the nearest plate.
+ */
+int InitSurface()
+{
+    register short	dx, dy;		/* x, y distance */
+    register long	dist;		/* distance */
+    register short	x, y;		/* location on surface */
+    register Plate_t	*pl;		/* plate pointer */
+    register Plate_t	*bestpl;	/* closest plate */
+    register long	bestdist;	/* distance of closest plate */
+    register int	i;		/* plate counter */
+
+    bestpl = NULL;
+
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            bestdist = 2 * tectonic.xsize * tectonic.ysize;
+            for (pl = &plates[0], i = 0; i < tectonic.nplates; ++i, ++pl) {
+                dx = pl->dx - x;
+                if (dx < 0)
+                    dx = -dx;
+                if (dx > tectonic.xsize/2)
+                    dx = tectonic.xsize - dx;
+                dy = pl->dy - y;
+                if (dy < 0)
+                    dy = -dy;
+                if (dy > tectonic.ysize/2)
+                    dy = tectonic.ysize - dy;
+                dist = dx * dx + dy * dy;
+                if (dist < bestdist) {
+                    bestdist = dist;
+                    bestpl = pl;
+                }
+            }
+            surface[x][y] = AllocRock(bestpl);
+        }
+    }
+    return 0;
+}
+
+/*
+ * Place some hot spots randomly.
+ */
+int SeedHotSpots()
+{
+    register int	i;	/* hot spot counter */
+    register Hotspot_t	*hsp;	/* hot spot pointer */
+
+    for (hsp = &hotspots[0], i = 0; i < tectonic.nhotspots; ++i, ++hsp) {
+        hsp->x = Rnd(tectonic.xsize);
+        hsp->y = Rnd(tectonic.ysize);
+        hsp->howhot = (Rnd(tectonic.hotspotheight) + Rnd(tectonic.hotspotheight) +
+          Rnd(tectonic.hotspotheight) + Rnd(tectonic.hotspotheight) + 2) >> 1;
+    }
+    return 0;
+}
+
+/*
+ * All initialization.
+ */
+int Tec_Init()
+{
+    nplates = tectonic.nplates;
+    SeedPlates();
+    InitSurface();
+    SeedHotSpots();
+    return 0;
+}
+
+/*
+ * ---------- Land movement --------------------------------------------------
+ */
+/*
+ * Assign each of the plates a direction and distance (velocity) to move.
+ * Velocity is added to previous value, but isn't allowed to exceed
+ * tectonic.epochmove in any direction.
+ */
+int AssignDirections()
+{
+    register int	i;	/* plate counter */
+    register Plate_t	*pl;	/* ptr to plates */
+    float		dist;	/* magnitude of vector */
+    register int	dir;	/* direction of vector */
+#define DEGtoRAD	(3.1415926 / 180.0)
+
+    for (pl = &plates[0], i = 0; i < nplates; ++i, ++pl) {
+        dir = Rnd(360);
+        dist = (float)(Rnd(101) + Rnd(101) + Rnd(101) - 150) *
+          (float)tectonic.epochmove/150.0;
+        pl->xvec += dist * cos(dir * DEGtoRAD);
+        pl->yvec += dist * sin(dir * DEGtoRAD);
+        if ((dist = hypot(pl->xvec, pl->yvec)) > (float)tectonic.epochmove) {
+            dist = (float)tectonic.epochmove / dist;
+            pl->xvec *= dist;
+            pl->yvec *= dist;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Set plates' dx,dy to the vector given by (i+1)*v/tectonic.epochmove - i*v/tectonic.epochmove,
+ * where v = plate's (xvec,yvec) vector.  This arrangement makes the sum of
+ * (dx,dy) over an epoch equal to (xvec,yvec).
+ */
+int SetMovementVectors(iter)
+  int iter;	/* which iteration */
+{
+    register int	i;	/* plate counter */
+    register Plate_t	*pl;	/* ptr to plates */
+
+    for (pl = &plates[0], i = 0; i < nplates; ++i, ++pl) {
+        pl->dx = (short)((iter + 1) * pl->xvec / tectonic.epochmove) -
+          (short)(iter * pl->xvec / tectonic.epochmove);
+        pl->dy = (short)((iter + 1) * pl->yvec / tectonic.epochmove) -
+          (short)(iter * pl->yvec / tectonic.epochmove);
+    }
+    return 0;
+}
+
+/*
+ * Move each rock according to its plate's movement vector.
+ * Use the rock's 'next' field to keep track of rocks that pile up.
+ */
+int MovePlates()
+{
+    register int	x, y;		/* where in the world */
+    register int	newx, newy;	/* rock's new home */
+    register Rock_t	*rp;		/* rock pointer */
+    register Rock_t	*prevrp;	/* rock before rp */
+    register Rock_t	*nextrp;	/* rock after rp */
+
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            prevrp = NULL;
+            for (rp = surface[x][y]; rp; prevrp = rp, rp = nextrp) {
+                nextrp = rp->next;
+                if (rp->moved)
+                    continue;
+                /*
+                 * Figure out where to move rock.
+                 */
+                rp->moved = TRUE;
+                if ((rp->plate->dx == 0) && (rp->plate->dy == 0))
+                    continue;
+                newx = Wrap_x(x + rp->plate->dx);
+                newy = Wrap_y(y + rp->plate->dy);
+                /*
+                 * Move rock.
+                 */
+                if (prevrp == NULL)
+                    surface[x][y] = rp->next;
+                else
+                    prevrp->next = rp->next;
+                rp->next = surface[newx][newy];
+                surface[newx][newy] = rp;
+            }
+        }
+    }
+    return 0;
+}
+
+/*
+ * ---------- Mountain building and the like ---------------------------------
+ */
+
+/*
+ * Create land where plates have spread apart.
+ */
+int Rift(x, y)
+  int x, y;
+{
+    register Plate_t	*pl;	/* which plate new land goes with */
+    register int	px, py;	/* offset at which to look for plate */
+    register long	tries;	/* # of failures to find plate */
+    register Rock_t	*rp;	/* new rock */
+
+    pl = NULL;
+
+    /*
+     * Find a plate to go with.
+     */
+    for (tries = 0; tries < 30; ++tries) {
+        px = Wrap_x(x + Rnd(3) - 1);
+        py = Wrap_y(y + Rnd(3) - 1);
+        if ((rp = surface[px][py]) != NULL) {
+            pl = rp->plate;
+            break;
+        }
+    }
+    /*
+     * Can't find a plate; start a new one.
+     */
+    if (pl == NULL) {
+        if (nplates < tectonic.maxplates)
+            ++nplates;
+        pl = &plates[nplates - 1];
+        pl->xvec = pl->yvec = 0.0;
+        pl->dx = pl->dy = 0;
+        pl->continent = FALSE;
+    }
+    /*
+     * Make rock.
+     */
+    rp = AllocRock(pl);
+    rp->elev = tectonic.riftelev;
+    rp->minerals = tectonic.riftminerals;	/* should distinguish between ocean and continental rifts!!! */
+    surface[x][y] = rp;
+    return 0;
+}
+
+/*
+ * Raise (or lower) land near x,y by height.
+ * Determine direction from x,y by rp's plate's vector.
+ */
+int ElevNearby(x, y, rp, height)
+  int x, y;
+  Rock_t *rp;
+  short height;
+{
+    float	h;	/* hypotenuse of rp->plate->vec */
+    int		x2, y2;	/* rock to raise */
+
+    h = hypot(rp->plate->xvec, rp->plate->yvec);
+    if (h < 0.01) {
+        x2 = x;
+        y2 = y;
+    } else {
+        x2 = Wrap_x(x + (int)(rp->plate->xvec / h + 1.5) - 1);
+        y2 = Wrap_y(y + (int)(rp->plate->yvec / h + 1.5) - 1);
+    }
+    if (surface[x2][y2])
+        surface[x2][y2]->elev += height;
+    return 0;
+}
+
+/*
+ * Continent hits continent; mountains are pushed up.
+ * New height = taller + 0.5 * shorter.  The leftover height is
+ * distributed to other rocks in the area.
+ */
+int Fold(x, y)
+  int x, y;
+{
+    register Rock_t	*rp0;		/* first rock on list */
+    register Rock_t	*rp1;		/* short rock */
+    register Rock_t	*rp2;		/* tall rock */
+    register short	halfshort;	/* half the short elevation */
+
+    rp0 = surface[x][y];
+    if (rp0->next->elev > rp0->elev) {
+        rp1 = rp0;
+        rp2 = rp1->next;
+    } else {
+        rp2 = rp0;
+        rp1 = rp2->next;
+    }
+    halfshort = (rp1->elev >> 1) * tectonic.foldfactor;
+    ElevNearby(x, y, rp1, (halfshort + 1) >> 1);
+    ElevNearby(x, y, rp2, halfshort >> 1);
+    /*
+     * Combine rocks and free a rock structure.
+     */
+    rp0->elev = rp2->elev + halfshort;
+    rp0->minerals = (rp1->minerals + rp2->minerals + 1) >> 1;
+    rp0->plate = Rnd(2) ? rp1->plate : rp2->plate;
+
+    rp1 = rp0->next;
+    rp0->next = rp1->next;
+    rp1->next = freeRockList;
+    freeRockList = rp1;
+    return 0;
+}
+
+/*
+ * Create a costal range where oceanic plate is subsumed by continental
+ * plate.  Simply add a constant height and minerals to the continent.
+ */
+int Subsume(x, y)
+  int x, y;
+{
+    register Rock_t	*rp0;		/* first rock on list */
+    register Rock_t	*rp1;		/* underwater rock */
+    register Rock_t	*rp2;		/* higher rock */
+
+    rp0 = surface[x][y];
+    if (rp0->next->elev > rp0->elev) {
+        rp1 = rp0;
+        rp2 = rp1->next;
+    } else {
+        rp2 = rp0;
+        rp1 = rp2->next;
+    }
+    ElevNearby(x, y, rp2, tectonic.trenchheight);
+    if (rp2->elev < 0)
+        rp0->minerals = rp2->minerals + tectonic.archipminerals;
+    else
+        rp0->minerals = rp2->minerals + tectonic.subsumeminerals;
+    rp0->elev = rp2->elev + tectonic.subsumeheight;
+    rp0->plate = rp2->plate;
+
+    rp1 = rp0->next;
+    rp0->next = rp1->next;
+    rp1->next = freeRockList;
+    freeRockList = rp1;
+    return 0;
+}
+
+/*
+ * For each spot on the surface, combine rocks which were piled on top of
+ * each other in MovePlates() into mountains,
+ * and create rifts where plates have spread apart leaving nothing.
+ */
+int MountainBuild()
+{
+    register int	x, y;		/* where in the world */
+    register Rock_t	*rp;		/* rock pointer */
+    register Rock_t	*rp2;		/* another rock pointer */
+
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            rp = surface[x][y];
+            if (rp == NULL)
+                Rift(x, y);
+            else while ((rp2 = rp->next) != NULL) {
+                if ((rp->elev > 0) && (rp2->elev > 0))
+                    Fold(x, y);		/* land + land */
+                else
+                    Subsume(x, y);	/* land or ocean + ocean */
+            }
+        }
+    }
+    return 0;
+}
+
+/*
+ * Increase elevation of hot spots.  If underwater, increase minerals.
+ */
+int EruptHotSpots()
+{
+    register int	i;	/* hot spot counter */
+    register Hotspot_t	*hsp;	/* hot spot pointer */
+    register Rock_t	*rp;	/* rock pointer */
+
+    for (hsp = &hotspots[0], i = 0; i < tectonic.nhotspots; ++i, ++hsp) {
+        rp = surface[hsp->x][hsp->y];
+        if (rp->elev <= 0)
+            rp->minerals += tectonic.hotspotminerals;
+        rp->elev += hsp->howhot;
+    }
+    return 0;
+}
+
+/*
+ * Wear down mountains.  Amount of wear is proportional to the average
+ * difference in height between a rock and the surrounding rocks,
+ * except very tall mountains don't erode much (no weather),
+ * there's more erosion around seashores (waves), and underwater
+ * mountains don't erode much.
+ * Also lower sea floors.
+ * Mark everything unmoved.
+ */
+int Erode()
+{
+    register int	x, y;		/* where in the world */
+    register Rock_t	*rp0;		/* rock pointer */
+    register Rock_t	*rp1;		/* pointer to nearby rock */
+    register short	elev0, elev1;	/* elevation of rp0, rp1 */
+    register int	i, j;		/* indices to nearby rocks */
+    register short	diff;		/* difference in height, roughly */
+    register long	depth;		/* average height of area */
+    int			diffplates;	/* nearby rocks belonging to other plates */
+    int			deepplates;	/* # of nearby rocks under water */
+
+    rp1 = NULL;
+
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            rp0 = surface[x][y];
+            elev0 = rp0->elev;
+            depth = elev0;
+            if (elev0 < 0)
+                elev0 = elev0 * tectonic.submergefactor;
+            else if (elev0 > tectonic.skyelev)
+                elev0 = tectonic.skyelev;
+            diffplates = 0;
+            deepplates = 0;
+            for (i = -1; i <= 1; ++i) {
+                for (j = -1; j <= 1; ++j) {	/* for each surrounding rock */
+                    if ((i == 0) && (j == 0))
+                        continue;
+                    rp1 = surface[Wrap_x(x + i)][Wrap_y(y + j)];
+                    elev1 = rp1->elev;
+                    if (rp1->plate != rp0->plate)
+                        ++diffplates;
+                    depth += elev1;
+                    if (elev1 < 0) {
+                        ++deepplates;
+                        elev1 = elev1 * tectonic.submergefactor;
+                    } else if (elev1 > tectonic.skyelev)
+                        elev1 = tectonic.skyelev;
+                    /*
+                     * Erode according to diff between elev0, elev1.
+                     */
+                    diff = elev0 - elev1;
+                    if ((elev0 <= 0 && elev1 >= 0) ||
+                      (elev0 >= 0 && elev1 <= 0)) {
+                        diff += tectonic.waveaction;
+                    }
+                    diff = tectonic.erodefactor * diff + 0.5;
+                    rp0->elevchange -= diff;
+                    rp1->elevchange += diff;
+                }
+            }
+            /*
+             * If 7/8 of the rocks surrounding us belong to different
+             * plates, join the crowd.
+             */
+            if (diffplates >= 7) {
+                do {
+                    i = Rnd(3) - 2;
+                    j = Rnd(3) - 2;
+                    if (i == 0 && j == 0)
+                        continue;
+                    rp1 = surface[Wrap_x(x + i)][Wrap_y(y + j)];
+                } while (rp1->plate == rp0->plate);
+                rp0->plate = rp1->plate;
+            }
+            /*
+             * Compute subsidence of ocean basins.
+             */
+            if (deepplates >= (rp0->elev >= 0 ? 8 : 6)) {
+                rp0->elevchange -= tectonic.subsidefactor * (depth/9 - tectonic.basinelev);
+            }
+        }
+    }
+    /*
+     * Incorporate elevchange; mark things moved.
+     */
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            rp0 = surface[x][y];
+            rp0->moved = FALSE;
+            rp0->elev += rp0->elevchange;
+            rp0->elevchange = 0;
+        }
+    }
+    return 0;
+}
+
+/*
+ * Give all the plates directions, move them, and see what happens.
+ * They may move a maximum of tectonic.epochmove cells per epoch.
+ */
+int Epoch()
+{
+    register int i;
+
+    AssignDirections();
+    for (i = 0; i < tectonic.epochmove; ++i) {
+        SetMovementVectors(i);
+        MovePlates();
+        MountainBuild();
+        EruptHotSpots();
+        Erode();
+    }
+    return 0;
+}
+
+/*************************************************************************
+ This ends Mark's plate tectonic code 
+ *************************************************************************/
+
+/**************************************************************************
+  mapgenerator_tectonic: Use Mark Isaak's plate tectonic simulation code 
+                         to generate a realistic world.
+**************************************************************************/
+static void mapgenerator_tectonic(void)
+{
+  int i;
+  int minval=5000000;
+  height_map=fc_malloc (sizeof(int)*map.xsize*map.ysize);
+
+  adjust_terrain_param();
+ 
+  /* Now, call Mark's teconic simulator to create a height map */
+
+  init_tec_data();
+  Tec_Init();
+  for(i=0;i<45;i++)
+      Epoch();
+
+  /* Convert the tectonically-synthsized map in to a freeciv height field */
+
+  whole_map_iterate(x, y) {
+    hmap(x, y) = surface[x][y]->elev;
+  } whole_map_iterate_end;
+
+  /* Mark's code generates negative values; adjust
+     To do: Add code which uses Mark's idea of what should be land
+            and water to determine where the oceans go; modify Mark's
+	    code to use map.landpercent */
+  minval = 600000;
+
+  whole_map_iterate(x, y) {
+
+    /* Hackish code to discard some more extreme values */
+    if (hmap(x, y) < -400) {
+      hmap(x, y) = -400;
+      }
+    if (hmap(x, y) > 10000) {
+      hmap(x, y) = 10000;
+      }
+
+    if (hmap(x, y) < minval) {
+      minval = hmap(x, y);
+      }
+  } whole_map_iterate_end;
+
+  if(minval < 0) {
+      whole_map_iterate(x, y) {
+          hmap(x, y) -= minval;
+	  } whole_map_iterate_end;
+      }
+
+  /* If we are using map generator eight, make the pure plate tectonic
+     land more lumpy.  We do this because the plate tectonic code simulates
+     the Earth's processes too well to make a traditional FreeCiv game: It
+     makes large stretches of land and water instead of the FreeCiv 
+     model of having many islands.  
+
+     The alleviates this by adding some lumpyness to the generated land;
+     this makes the continents smaller and the islands more numerous */
+
+  if(map.generator == 8) {
+      for (i=0;i<(map.xsize*map.ysize)/2;i++) {
+          int x,y;
+	  rand_map_pos(&x, &y);
+	  hmap(x, y) += myrand(4000);
+	  }
+
+      /* Smooth things out just a tad */
+      smooth_map();
+      smooth_map();
+      }
+
+  /* Find the minval and maxval now that we have made a plate tectonic
+     simulated map */
+
+  whole_map_iterate(x, y) {
+    if (hmap(x, y) > maxval)
+      maxval = hmap(x, y);
+    if (hmap(x, y) < minval)
+      minval = hmap(x, y);
+  } whole_map_iterate_end;
+
+  maxval-=minval;
+  adjust_map(minval);
+
+  /* based on map.landpercent, separate land from water */
+  make_land(maxval / 5);
+
   free(height_map);
   height_map = NULL;
 }
@@ -2211,7 +3037,7 @@
   maxval -= minval;
   adjust_map(minval);
   
-  make_land();
+  make_land(maxval);
   free(height_map);
   height_map = NULL;
 }
@@ -2256,7 +3082,7 @@
 }
 
 /* Creates a peninsula and put the player's starting position
-   on it */
+   on it; this is used by map generator 6 */
 static void create_peninsula(int x, int y,int player_number,
 			     int width, int height,int direction,
 			     int remaining_count)
