diff -urw freeciv-1.14.0/common/game.c freeciv/common/game.c
--- freeciv-1.14.0/common/game.c	2002-10-11 19:35:13.000000000 -0400
+++ freeciv/common/game.c	2003-04-02 18:22:40.000000000 -0500
@@ -714,6 +714,11 @@
   game.watchtower_extra_vision=GAME_DEFAULT_WATCHTOWER_EXTRA_VISION,
   game.allowed_city_names = GAME_DEFAULT_ALLOWED_CITY_NAMES;
 
+  game.slowai_tech = GAME_DEFAULT_SLOWAI_TECH;
+  game.slowai_grow = GAME_DEFAULT_SLOWAI_GROW;
+  game.check_isles = GAME_DEFAULT_CHECK_ISLES;
+  game.best_isles = GAME_DEFAULT_BEST_ISLES;
+
   sz_strlcpy(game.rulesetdir, GAME_DEFAULT_RULESETDIR);
 
   game.firepower_factor = 1;
diff -urw freeciv-1.14.0/common/game.h freeciv/common/game.h
--- freeciv-1.14.0/common/game.h	2002-10-11 19:35:13.000000000 -0400
+++ freeciv/common/game.h	2003-04-02 18:25:13.000000000 -0500
@@ -217,6 +217,11 @@
     bool load_private_map; /* Only makes sense if the players are loaded. */
     bool load_settings;
   } load_options;
+
+   int slowai_tech;  /* AI gains tech slower then normal. */
+   int slowai_grow;  /* AI grows slower then normal. */
+   int check_isles;  /* Make sure there each player gets their own island. */
+   bool best_isles;  /* Make sure players get best islands. */
 };
 
 /* Unused? */
@@ -455,4 +460,15 @@
 
 #define GAME_START_YEAR -4000
 
+#define GAME_DEFAULT_SLOWAI_TECH 1
+#define GAME_MIN_SLOWAI_TECH 1
+#define GAME_MAX_SLOWAI_TECH 4
+#define GAME_DEFAULT_SLOWAI_GROW 100
+#define GAME_MIN_SLOWAI_GROW 25
+#define GAME_MAX_SLOWAI_GROW 100
+#define GAME_DEFAULT_CHECK_ISLES 0
+#define GAME_MIN_CHECK_ISLES 0
+#define GAME_MAX_CHECK_ISLES 30  /* Max # of players. */
+#define GAME_DEFAULT_BEST_ISLES FALSE
+
 #endif  /* FC__GAME_H */
diff -urw freeciv-1.14.0/common/map.h freeciv/common/map.h
--- freeciv-1.14.0/common/map.h	2002-10-11 19:35:13.000000000 -0400
+++ freeciv/common/map.h	2003-04-02 18:25:45.000000000 -0500
@@ -619,7 +619,7 @@
 
 #define MAP_DEFAULT_GENERATOR    1
 #define MAP_MIN_GENERATOR        1
-#define MAP_MAX_GENERATOR        5
+#define MAP_MAX_GENERATOR        8
 
 #define MAP_DEFAULT_TINYISLES    FALSE
 #define MAP_MIN_TINYISLES        FALSE
diff -urw freeciv-1.14.0/common/rand.c freeciv/common/rand.c
--- freeciv-1.14.0/common/rand.c	2002-03-13 05:40:00.000000000 -0500
+++ freeciv/common/rand.c	2003-04-02 19:05:20.000000000 -0500
@@ -1,148 +1,127 @@
-/********************************************************************** 
- Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
-   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.
-***********************************************************************/
-
-/*************************************************************************
-   The following random number generator can be found in _The Art of 
-   Computer Programming Vol 2._ (2nd ed) by Donald E. Knuth. (C)  1998.
-   The algorithm is described in section 3.2.2 as Mitchell and Moore's
-   variant of a standard additive number generator.  Note that the
-   the constants 55 and 24 are not random.  Please become familiar with
-   this algorithm before you mess with it.
-
-   Since the additive number generator requires a table of numbers from
-   which to generate its random sequences, we must invent a way to 
-   populate that table from a single seed value.  I have chosen to do
-   this with a different PRNG, known as the "linear congruential method" 
-   (also found in Knuth, Vol2).  I must admit that my choices of constants
-   (3, 257, and MAX_UINT32) are probably not optimal, but they seem to
-   work well enough for our purposes.
-   
-   Original author for this code: Cedric Tefft <cedric@earthling.net>
-   Modified to use rand_state struct by David Pfitzner <dwp@mso.anu.edu.au>
-*************************************************************************/
-
 #include <assert.h>
-
-#include "log.h"
-#include "shared.h"		/* TRUE, FALSE */
+#include <string.h>
+#include <sys/types.h>
 
 #include "rand.h"
+#include "log.h"
+#include "shared.h"
 
+BYTE r_inBlock[17],r_binKey[17];
+BYTE r_keyMaterial[320]; /* We may not eventually need this */
+keyInstance r_keyInst;
+cipherInstance r_cipherInst;
 
-/* A global random state:
- * Initialized by mysrand(), updated by myrand(),
- * Can be duplicated/saved/restored via get_myrand_state()
- * and set_myrand_state().
- */
 static RANDOM_STATE rand_state;
 
-/*************************************************************************
-  Returns a new random value from the sequence, in the interval 0 to
-  (size-1) inclusive, and updates global state for next call.
-  size==0 means result will be within 0 to MAX_UINT32 inclusive.
-
-  Once we calculate new_rand below uniform (we hope) between 0 and
-  MAX_UINT32 inclusive, need to reduce to required range.  Using
-  modulus is bad because generators like this are generally less
-  random for their low-significance bits, so this can give poor
-  results when 'size' is small.  Instead want to divide the range
-  0..MAX_UINT32 into (size) blocks, each with (divisor) values, and
-  for any remainder, repeat the calculation of new_rand.
-  Then:
-	 return_val = new_rand / divisor;
-  Will repeat for new_rand > max, where:
-         max = size * divisor - 1
-  Then max <= MAX_UINT32 implies
-	 size * divisor <= (MAX_UINT32+1)
-  thus   divisor <= (MAX_UINT32+1)/size
-  
-  Need to calculate this divisor.  Want divisor as large as possible
-  given above contraint, but it doesn't hurt us too much if it is a
-  bit smaller (just have to repeat more often).  Calculation exactly
-  as above is complicated by fact that (MAX_UINT32+1) may not be
-  directly representable in type RANDOM_TYPE, so we do instead:
-         divisor = MAX_UINT32/size
-*************************************************************************/
-RANDOM_TYPE myrand(RANDOM_TYPE size) 
-{
-  RANDOM_TYPE new_rand, divisor=1, max=MAX_UINT32;
-  int bailout = 0;
-
-  assert(rand_state.is_init);
-    
-  if (size>1) {
-    divisor = MAX_UINT32/size;
-    max = size * divisor - 1;
-  }
-
-  do {
-    new_rand = (rand_state.v[rand_state.j]
-		+ rand_state.v[rand_state.k]) & MAX_UINT32;
-
-    rand_state.x = (rand_state.x +1) % 56;
-    rand_state.j = (rand_state.j +1) % 56;
-    rand_state.k = (rand_state.k +1) % 56;
-    rand_state.v[rand_state.x] = new_rand;
-
-    if (++bailout > 10000) {
-      freelog(LOG_ERROR, "Bailout in myrand(%u)", size);
-      new_rand = 0;
-      break;
-    }
-
-  } while (new_rand > max && size > 1);
-
-  if (size > 1) {
-    new_rand /= divisor;
-  } else if (size == 1) {
-    new_rand = 0;
-  }
-  /* else leave it "raw" */
-
-  /* freelog(LOG_DEBUG, "rand(%u) = %u", size, new_rand); */
 
-  return new_rand;
+/* A cryptgraphically secure random number with a value between
+   0 and 2^31 
+   Input: None
+   Output: A number between 0 and 2^32 - 1
+*/
+u_int32_t rng_raw() {
+    u_int32_t nummake;
+    int rp;
+
+    /* If needed, rerun the encryption to create 128 more random bits */
+    if(rand_state.r_place > 12) {
+        rp = 15;
+        nummake = ++rand_state.dice_counter;
+	/* Make sure the dice counter can not step on the seed */
+	nummake %= 10000000;
+	while(rp > 0 && nummake > 0) {
+            r_inBlock[rp] = '0' + nummake % 10;
+	    nummake /= 10;
+	    rp--;
+	    }
+#ifdef DEBUG
+        printf("\nNEW BLOCK ");
+        for(rp = 0; rp < 16; rp++) {
+	    printf("%c",r_inBlock[rp]);
+	    }
+        printf("\n");
+#endif /* DEBUG */
+        blockEncrypt(&r_cipherInst,&r_keyInst,r_inBlock,128,rand_state.v);
+#ifdef DEBUG
+        for(rp = 0; rp < 16; rp++) {
+	    printf("%2x ",rand_state.v[r_place]);
+	    }
+        printf("END NEW BLOCK\n");
+#endif /* DEBUG */
+	rand_state.r_place = 0;
+	}
+    nummake = (rand_state.v[rand_state.r_place] & 0xff);
+    rand_state.r_place++;
+    nummake <<= 8;
+    nummake |= (rand_state.v[rand_state.r_place] & 0xff);
+    rand_state.r_place++;
+    nummake <<= 8;
+    nummake |= (rand_state.v[rand_state.r_place] & 0xff);
+    rand_state.r_place++;
+    nummake <<= 8;
+    nummake |= (rand_state.v[rand_state.r_place] & 0xff);
+    rand_state.r_place++;
+    nummake <<= 8;
+    nummake |= (rand_state.v[rand_state.r_place] & 0xff);
+    return nummake;
+    }
+
+/* Return a number from 1 to n; we make sure this is good */
+RANDOM_TYPE myrand(RANDOM_TYPE n) {
+    u_int32_t r;
+    if(n <= 0 || n > 2000000000) {
+        return rng_raw();
+	}
+    r = rng_raw();
+    while(r > 4294967296 - n) {
+        r = rng_raw();
+	}
+    return r % n;
+    }
+
+/* Initialize the cryptographically secure psudo-random-number generator */
+/* Input: pointer to string that has binary crypto key */
+
+int init_rng_g(char *key) {
+    unsigned char crypto_key[34];
+    /* Initialize the keys, including the "binKey" (is this used?) */
+    memset(r_binKey,'0',16);
+    memset(crypto_key,'0',33);
+    strncpy(crypto_key,key,32);
+
+    if(makeKey(&r_keyInst, DIR_ENCRYPT, 128, crypto_key) != 1)
+	return -1;
+    if(cipherInit(&r_cipherInst, MODE_ECB, NULL) != 1)
+	return -1;
+    if(blockEncrypt(&r_cipherInst,&r_keyInst,r_inBlock,128,rand_state.v)!=128)
+	return -1;
+    
+    return 1;
+    }
+
+void mysrand(RANDOM_TYPE seed) {
+
+    int counter;
+
+    /* Set the plaintext block to '0000000000000000' */
+    memset(r_inBlock,'0',16);
+
+    /* Make sure the seed can not step on the dice rolls */
+    /* seed %= 1000000000; */
+
+    /* Put the seed in the block which we encrypt in counter mode (A seed of
+       1 makes the plaintext clock look like '1000000000000000', a seed of 256
+       makes the plaintext look like '6520000000000000', and so on */
+    counter = 0;
+    while(seed > 0 && counter < 16) {
+        r_inBlock[counter] = '0' + seed % 10;
+	seed /= 10;
+	counter++;
 } 
 
-/*************************************************************************
-  Initialize the generator; see comment at top of file.
-*************************************************************************/
-void mysrand(RANDOM_TYPE seed) 
-{ 
-    int  i; 
-
-    rand_state.v[0]=(seed & MAX_UINT32);
+    /* Initialize the crypto with a fixed key and the above seed */
+    init_rng_g("1970012508675309");
 
-    for(i=1; i<56; i++) {
-       rand_state.v[i] = (3 * rand_state.v[i-1] + 257) & MAX_UINT32;
-    }
-
-    rand_state.j = (55-55);
-    rand_state.k = (55-24);
-    rand_state.x = (55-0);
-
-    rand_state.is_init = TRUE;
-
-    /* Heat it up a bit:
-     * Using modulus in myrand() this was important to pass
-     * test_random1().  Now using divisor in myrand() that particular
-     * test no longer indicates problems, but this seems a good idea
-     * anyway -- eg, other tests could well reveal other initial
-     * problems even using divisor.
-     */
-    for (i=0; i<10000; i++) {
-      (void) myrand(0);
-    }
 } 
 
 /*************************************************************************
@@ -208,3 +187,430 @@
   /* restore state: */
   set_myrand_state(saved_state);
 }
+
+/* Now the nuts and bolts; here be dragons */
+
+/* Copyright (c) 2002,2003 Sam Trenholme
+ *
+ * TERMS
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * This software is provided 'as is' with no guarantees of correctness or
+ * fitness for purpose.
+ *
+ * Note that this copyrighted code is based on public domain code
+ */
+
+
+/**
+ * rng-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Note: This is a Rijndael variant.
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * The original code was hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+static const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+int rngKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+   	int i = 0;
+	u32 temp;
+
+	rk[0] = GETU32(cipherKey     );
+	rk[1] = GETU32(cipherKey +  4);
+	rk[2] = GETU32(cipherKey +  8);
+	rk[3] = GETU32(cipherKey + 12);
+	if (keyBits == 128) {
+		for (;;) {
+			temp  = rk[3];
+			rk[4] = rk[0] ^
+				(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+				(Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+				(Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+				(Te4[(temp >> 24)       ] & 0x000000ff) ^
+				rcon[i];
+			rk[5] = rk[1] ^ rk[4];
+			rk[6] = rk[2] ^ rk[5];
+			rk[7] = rk[3] ^ rk[6];
+			if (++i == 10) {
+				return 10;
+			}
+			rk += 4;
+		}
+	}
+	exit(1);
+}
+
+void rngEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(pt     ) ^ rk[0];
+	s1 = GETU32(pt +  4) ^ rk[1];
+	s2 = GETU32(pt +  8) ^ rk[2];
+	s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+   	/* round 2: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+    /* round 3: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+   	/* round 4: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+    /* round 5: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+   	/* round 6: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+    /* round 7: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+   	/* round 8: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+    /* round 9: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    }
+    rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+	 * Nr - 1 full rounds:
+	 */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 =
+		(Te4[(t0 >> 24)       ] & 0xff000000) ^
+		(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t3      ) & 0xff] & 0x000000ff) ^
+		rk[0];
+	PUTU32(ct     , s0);
+	s1 =
+		(Te4[(t1 >> 24)       ] & 0xff000000) ^
+		(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t0      ) & 0xff] & 0x000000ff) ^
+		rk[1];
+	PUTU32(ct +  4, s1);
+	s2 =
+		(Te4[(t2 >> 24)       ] & 0xff000000) ^
+		(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t1      ) & 0xff] & 0x000000ff) ^
+		rk[2];
+	PUTU32(ct +  8, s2);
+	s3 =
+		(Te4[(t3 >> 24)       ] & 0xff000000) ^
+		(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+		(Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+		(Te4[(t2      ) & 0xff] & 0x000000ff) ^
+		rk[3];
+	PUTU32(ct + 12, s3);
+}
+
+/* Copyright (c) 2002,2003 Sam Trenholme
+ *
+ * TERMS
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * This software is provided 'as is' with no guarantees of correctness or
+ * fitness for purpose.
+ *
+ * Note that this copyrighted code is based on public domain code
+ */
+
+/**
+ * rng-api-fst.c
+ *
+ * @version 2.9 (December 2000)
+ * (Modified by Sam for MaraDNS use)
+ *
+ * Note: This is a Rijndael variant.
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ * @author Sam Trenholme <list-subscribe@maradns.org>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Acknowledgements:
+ *
+ * We are deeply indebted to the following people for their bug reports,
+ * fixes, and improvement suggestions to this implementation. Though we
+ * tried to list all contributions, we apologise in advance for any
+ * missing reference.
+ *
+ * Andrew Bales <Andrew.Bales@Honeywell.com>
+ * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ * John Skodon <skodonj@webquill.com>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+int makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) {
+	int i;
+	char *keyMat;
+	u8 cipherKey[MAXKB];
+	
+	if (key == NULL) {
+		return BAD_KEY_INSTANCE;
+	}
+
+	if (direction == DIR_ENCRYPT) {
+		key->direction = direction;
+	} else {
+		return BAD_KEY_DIR;
+	}
+
+	if (keyLen == 128) {
+		key->keyLen = keyLen;
+	} else {
+		return BAD_KEY_MAT;
+	}
+
+#ifdef ASCII_KEY
+        strncpy(key->keyMaterial, keyMaterial, keyLen/4);
+#else
+        memcpy(key->keyMaterial, keyMaterial, keyLen/8);
+#endif
+
+	/* initialize key schedule: */
+	keyMat = key->keyMaterial;
+ 	for (i = 0; i < key->keyLen/8; i++) {
+		int v;
+#ifdef ASCII_KEY
+		int t;
+		t = *keyMat++;
+		if ((t >= '0') && (t <= '9')) v = (t - '0') << 4;
+		else if ((t >= 'a') && (t <= 'f')) v = (t - 'a' + 10) << 4;
+		else if ((t >= 'A') && (t <= 'F')) v = (t - 'A' + 10) << 4;
+		else return BAD_KEY_MAT;
+		
+		t = *keyMat++;
+		if ((t >= '0') && (t <= '9')) v ^= (t - '0');
+		else if ((t >= 'a') && (t <= 'f')) v ^= (t - 'a' + 10);
+		else if ((t >= 'A') && (t <= 'F')) v ^= (t - 'A' + 10);
+		else return BAD_KEY_MAT;
+#else
+		v = *keyMat;
+		keyMat++;
+#endif /* ASCII_KEY */
+		cipherKey[i] = (u8)v;
+	}
+	if (direction == DIR_ENCRYPT) {
+		key->Nr = rngKeySetupEnc(key->rk, cipherKey, keyLen);
+	} else {
+		return -1;
+	}
+	rngKeySetupEnc(key->ek, cipherKey, keyLen);
+	return TRUE;
+}
+
+int cipherInit(cipherInstance *cipher, BYTE mode, char *IV) {
+	if (mode == MODE_ECB) {
+		cipher->mode = mode;
+	} else {
+		return BAD_CIPHER_MODE;
+	}
+	if (IV != NULL) {
+	        return BAD_CIPHER_MODE;
+	} else {
+		memset(cipher->IV, 0, MAX_IV_SIZE);
+	}
+	return TRUE;
+}
+
+int blockEncrypt(cipherInstance *cipher, keyInstance *key,
+		BYTE *input, int inputLen, BYTE *outBuffer) {
+	int i, numBlocks;
+
+	if (cipher == NULL ||
+		key == NULL ||
+		key->direction == DIR_DECRYPT) {
+		return BAD_CIPHER_STATE;
+	}
+	if (input == NULL || inputLen <= 0) {
+		return 0; /* nothing to do */
+	}
+
+	numBlocks = inputLen/128;
+	
+	switch (cipher->mode) {
+	case MODE_ECB:
+		for (i = numBlocks; i > 0; i--) {
+			rngEncrypt(key->rk, key->Nr, input, outBuffer);
+			input += 16;
+			outBuffer += 16;
+		}
+		break;
+		
+	default:
+		return BAD_CIPHER_STATE;
+	}
+	
+	return 128*numBlocks;
+}
+
diff -urw freeciv-1.14.0/common/rand.h freeciv/common/rand.h
--- freeciv-1.14.0/common/rand.h	2002-04-12 09:50:56.000000000 -0400
+++ freeciv/common/rand.h	2003-04-02 19:17:08.000000000 -0500
@@ -18,11 +18,13 @@
 /* This is duplicated in shared.h to avoid extra includes: */
 #define MAX_UINT32 0xFFFFFFFF
 
-typedef unsigned int RANDOM_TYPE;
+typedef u_int32_t RANDOM_TYPE;
+typedef unsigned char BYTE;
 
 typedef struct {
-  RANDOM_TYPE v[56];
-  int j, k, x;
+  BYTE v[16];
+  int dice_counter;
+  int r_place;
   bool is_init;			/* initially 0 for static storage */
 } RANDOM_STATE;
 
@@ -35,4 +37,531 @@
 
 void test_random1(int n);
 
+/* All of the RNG-specific stuff */
+
+/* Copyright (c) 2002,2003 Sam Trenholme
+ *
+ * TERMS
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * This software is provided 'as is' with no guarantees of correctness or
+ * fitness for purpose.
+ *
+ * Note that this code is based on public domain code 
+ */
+
+/**
+ * rng-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Note: This is a Rijndael variant.
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RNG_ALG_FST_H
+#define __RNG_ALG_FST_H
+
+#define MAXKC	(256/32)
+#define MAXKB	(256/8)
+#define MAXNR	14
+
+typedef unsigned char	u8;	
+typedef unsigned short	u16;	
+typedef unsigned int	u32;
+
+int rngKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+void rngEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]);
+
+#endif /* __RNG_ALG_FST_H */
+
+/* Copyright (c) 2002,2003 Sam Trenholme
+ *
+ * TERMS
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * This software is provided 'as is' with no guarantees of correctness or
+ * fitness for purpose.
+ *
+ * Note that this copyrighted code is based on public domain code
+ */
+
+/**
+ * rng-api-fst.h
+ *
+ * @version 2.9 (December 2000)
+ *
+ * Note: This is a Rijndael variant.
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Acknowledgements:
+ *
+ * We are deeply indebted to the following people for their bug reports,
+ * fixes, and improvement suggestions to this implementation. Though we
+ * tried to list all contributions, we apologise in advance for any
+ * missing reference.
+ *
+ * Andrew Bales <Andrew.Bales@Honeywell.com>
+ * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ * John Skodon <skodonj@webquill.com>
+ */
+
+#ifndef __RIJNDAEL_API_FST_H
+#define __RIJNDAEL_API_FST_H
+
+#include <stdio.h>
+
+/*  Generic Defines  */
+#define     DIR_ENCRYPT           0 /*  Are we encrpyting?  */
+#define     DIR_DECRYPT           1 /*  Are we decrpyting?  */
+#define     MODE_ECB              1 /*  Are we ciphering in ECB mode?   */
+#define     MODE_CBC              2 /*  Are we ciphering in CBC mode?   */
+#define     MODE_CFB1             3 /*  Are we ciphering in 1-bit CFB mode? */
+#ifndef TRUE
+#  define     TRUE                1
+#  define     FALSE               0
+#endif
+#define     BITSPERBLOCK        128 /* Default number of bits in a cipher block */
+
+/*  Error Codes  */
+#define     BAD_KEY_DIR          -1 /*  Key direction is invalid, e.g., unknown value */
+#define     BAD_KEY_MAT          -2 /*  Key material not of correct length */
+#define     BAD_KEY_INSTANCE     -3 /*  Key passed is not valid */
+#define     BAD_CIPHER_MODE      -4 /*  Params struct passed to cipherInit invalid */
+#define     BAD_CIPHER_STATE     -5 /*  Cipher in wrong state (e.g., not initialized) */
+#define     BAD_BLOCK_LENGTH     -6
+#define     BAD_CIPHER_INSTANCE  -7
+#define     BAD_DATA             -8 /*  Data contents are invalid, e.g., invalid padding */
+#define     BAD_OTHER            -9 /*  Unknown error */
+
+/*  Algorithm-specific Defines  */
+#define     MAX_KEY_SIZE         64 /* # of ASCII char's needed to represent a key */
+#define     MAX_IV_SIZE          16 /* # bytes needed to represent an IV  */
+
+/*  Typedefs  */
+
+/*  The structure for key information */
+typedef struct {
+    BYTE  direction;                /* Key used for encrypting or decrypting? */
+    int   keyLen;                   /* Length of the key  */
+    char  keyMaterial[MAX_KEY_SIZE+1];  /* Raw key data in ASCII, e.g., user input or KAT values */
+	int   Nr;                       /* key-length-dependent number of rounds */
+	u32   rk[4*(MAXNR + 1)];        /* key schedule */
+	u32   ek[4*(MAXNR + 1)];        /* CFB1 key schedule (encryption only) */
+} keyInstance;
+
+/*  The structure for cipher information */
+typedef struct {                    /* changed order of the components */
+    BYTE  mode;                     /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
+    BYTE  IV[MAX_IV_SIZE];          /* A possible Initialization Vector for ciphering */
+} cipherInstance;
+
+/*  Function prototypes  */
+
+int makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial);
+
+int cipherInit(cipherInstance *cipher, BYTE mode, char *IV);
+
+int blockEncrypt(cipherInstance *cipher, keyInstance *key,
+        BYTE *input, int inputLen, BYTE *outBuffer);
+
+int padEncrypt(cipherInstance *cipher, keyInstance *key,
+		BYTE *input, int inputOctets, BYTE *outBuffer);
+
+int blockDecrypt(cipherInstance *cipher, keyInstance *key,
+        BYTE *input, int inputLen, BYTE *outBuffer);
+
+int padDecrypt(cipherInstance *cipher, keyInstance *key,
+		BYTE *input, int inputOctets, BYTE *outBuffer);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+int cipherUpdateRounds(cipherInstance *cipher, keyInstance *key,
+        BYTE *input, int inputLen, BYTE *outBuffer, int Rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
+
+#endif /* __RIJNDAEL_API_FST_H */
+
+/* The tables for the RNG core */
+static const u32 Te0[256] = {
+0xb3e2509bU, 0x63b4ca06U, 0x85e4a2d4U, 0x216c4602U, 
+0x3a6f3fa8U, 0xa616bd75U, 0x134d0610U, 0x4d60b99cU, 
+0x176ab44dU, 0x7f41f98eU, 0xe277da8fU, 0xcdec08c9U, 
+0x5a0a0dd1U, 0x1b0379aaU, 0x7b664bd3U, 0xa1e0f757U, 
+0xfaa55b5aU, 0xea39a535U, 0xc5a27773U, 0xb17c0938U, 
+0x2023e7deU, 0xd47128c0U, 0x7c9001f1U, 0x22bdbe7dU, 
+0xec804ecbU, 0xb9327682U, 0xbd15c4dfU, 0xc9cbba94U, 
+0xa488e4d6U, 0x014fa1dcU, 0x60653279U, 0xfe82e907U, 
+0x74de7e4bU, 0xa8e12931U, 0x0427b25dU, 0xe65068d2U, 
+0x898d6f33U, 0x928e1699U, 0x1202a7ccU, 0x7a29ea0fU, 
+0x1f24cbf7U, 0x64428024U, 0xdd70f6a6U, 0xbec43ca0U, 
+0x2d058be5U, 0x15f4edeeU, 0x572c61eaU, 0x1cf53388U, 
+0xf974a325U, 0x4046d5a7U, 0x2bbc601bU, 0xdea10ed9U, 
+0x42d88c04U, 0x8f3484cdU, 0x5f621e50U, 0x835d492aU, 
+0xf51d6ec2U, 0x2f9bd246U, 0xbf8b9d7cU, 0xee1e1768U, 
+0x6c0cff9eU, 0x16251591U, 0x37495393U, 0x5cb3e62fU, 
+0x3f072c29U, 0x4bd95262U, 0x05681381U, 0x90104f3aU, 
+0x03d1f87fU, 0x5244726bU, 0xd53e891cU, 0x9ac06923U, 
+0x51958a14U, 0x915feee6U, 0xdfeeaf05U, 0x79f81270U, 
+0xd2c8c33eU, 0x39bec7d7U, 0x764027e8U, 0x4808aa1dU, 
+0xcf72516aU, 0x269a0c20U, 0xab30d14eU, 0xc2543d51U, 
+0x770f8634U, 0xa0af568bU, 0x27d5adfcU, 0x4ffee03fU, 
+0xb4141ab9U, 0x8ce57cb2U, 0x2af3c1c7U, 0xdbc91d58U, 
+0xd6ef7163U, 0x3cd6d456U, 0x5b45ac0dU, 0x3e488df5U, 
+0x32214012U, 0xe1a622f0U, 0x9b8fc8ffU, 0x43972dd8U, 
+0xcca3a915U, 0x286d9864U, 0x31f0b86dU, 0x3498abecU, 
+0x73283469U, 0x6fdd07e1U, 0x682b4dc3U, 0x66dcd987U, 
+0x5663c036U, 0x62fb6bdaU, 0x95785cbbU, 0xe71fc90eU, 
+0x726795b5U, 0xcb55e337U, 0x5dfc47f3U, 0x70f9cc16U, 
+0xb68a431aU, 0x81c31089U, 0xe4ce3171U, 0x0d266c3bU, 
+0xacc69b6cU, 0x985e3080U, 0xda86bc84U, 0x6d435e42U, 
+0x6964ec1fU, 0x06b9ebfeU, 0x84ab0308U, 0xbae38efdU, 
+0x11d35fb3U, 0x00000000U, 0x0ef79444U, 0xfbeafa86U, 
+0xbbac2f21U, 0x650d21f8U, 0xae58c2cfU, 0x86355aabU, 
+0x612a93a5U, 0xf452cf1eU, 0x446167faU, 0x877afb77U, 
+0xf3a4853cU, 0xa7591ca9U, 0x7ddfa02dU, 0x58945472U, 
+0x9c7982ddU, 0xd818e527U, 0x336ee1ceU, 0x07f64a22U, 
+0xa5c7450aU, 0x808cb155U, 0xb7c5e2c6U, 0xef51b6b4U, 
+0x3606f24fU, 0xffcd48dbU, 0x55b23849U, 0x6bfab5bcU, 
+0x4eb141e3U, 0x8e7b2511U, 0x6ab51460U, 0xfd531178U, 
+0x18d281d5U, 0xd38762e2U, 0xf2eb24e0U, 0xca1a42ebU, 
+0xdc3f577aU, 0x88c2ceefU, 0x8daadd6eU, 0x029e59a3U, 
+0x199d2009U, 0xb033a8e4U, 0x0901de66U, 0x0c69cde7U, 
+0x0fb83598U, 0xf7833761U, 0xf6cc96bdU, 0x78b7b3acU, 
+0x7591df97U, 0x49470bc1U, 0xe58190adU, 0x97e60518U, 
+0xd7a0d0bfU, 0x4a96f3beU, 0x9fa87aa2U, 0xe9e85d4aU, 
+0x0b9f87c5U, 0x452ec626U, 0xbc5a6503U, 0xd95744fbU, 
+0x9911915cU, 0x96a9a4c4U, 0x46ff3e59U, 0x4c2f1840U, 
+0x9437fd67U, 0xe3387b53U, 0x3d99758aU, 0xc73c2ed0U, 
+0x2c4a2a39U, 0x254bf45fU, 0x23f21fa1U, 0x1a4cd876U, 
+0xd0569a9dU, 0xb87dd75eU, 0x1dba9254U, 0x38f1660bU, 
+0xa2310f28U, 0x5e2dbf8cU, 0x47b09f85U, 0x14bb4c32U, 
+0xa9ae88edU, 0x50da2bc8U, 0x24045583U, 0xeb7604e9U, 
+0xb55bbb65U, 0x1e6b6a2bU, 0x8212e8f6U, 0xf13adc9fU, 
+0xc0ca64f2U, 0x084e7fbaU, 0xa37eaef4U, 0x35d70a30U, 
+0xedcfef17U, 0xe0e9832cU, 0x30bf19b1U, 0x9ee7db7eU, 
+0xe8a7fc96U, 0x93c1b745U, 0xfc1cb0a4U, 0xb2adf147U, 
+0x109cfe6fU, 0xad893ab0U, 0xaf176313U, 0x2ed4739aU, 
+0x6e92a63dU, 0x9d362301U, 0xf83b02f9U, 0xc6738f0cU, 
+0xc185c52eU, 0xc8841b48U, 0x6793785bU, 0xaa7f7092U, 
+0x4109747bU, 0xc31b9c8dU, 0x71b66dcaU, 0x8b133690U, 
+0xd1193b41U, 0x54fd9995U, 0xc4edd6afU, 0x7e0e5852U, 
+0x3b209e74U, 0x8a5c974cU, 0xf0757d43U, 0x59dbf5aeU, 
+0xce3df0b6U, 0x530bd3b7U, 0x0ad02619U, 0x292239b8U, 
+};
+static const u32 Te1[256] = {
+0x9bb3e250U, 0x0663b4caU, 0xd485e4a2U, 0x02216c46U, 
+0xa83a6f3fU, 0x75a616bdU, 0x10134d06U, 0x9c4d60b9U, 
+0x4d176ab4U, 0x8e7f41f9U, 0x8fe277daU, 0xc9cdec08U, 
+0xd15a0a0dU, 0xaa1b0379U, 0xd37b664bU, 0x57a1e0f7U, 
+0x5afaa55bU, 0x35ea39a5U, 0x73c5a277U, 0x38b17c09U, 
+0xde2023e7U, 0xc0d47128U, 0xf17c9001U, 0x7d22bdbeU, 
+0xcbec804eU, 0x82b93276U, 0xdfbd15c4U, 0x94c9cbbaU, 
+0xd6a488e4U, 0xdc014fa1U, 0x79606532U, 0x07fe82e9U, 
+0x4b74de7eU, 0x31a8e129U, 0x5d0427b2U, 0xd2e65068U, 
+0x33898d6fU, 0x99928e16U, 0xcc1202a7U, 0x0f7a29eaU, 
+0xf71f24cbU, 0x24644280U, 0xa6dd70f6U, 0xa0bec43cU, 
+0xe52d058bU, 0xee15f4edU, 0xea572c61U, 0x881cf533U, 
+0x25f974a3U, 0xa74046d5U, 0x1b2bbc60U, 0xd9dea10eU, 
+0x0442d88cU, 0xcd8f3484U, 0x505f621eU, 0x2a835d49U, 
+0xc2f51d6eU, 0x462f9bd2U, 0x7cbf8b9dU, 0x68ee1e17U, 
+0x9e6c0cffU, 0x91162515U, 0x93374953U, 0x2f5cb3e6U, 
+0x293f072cU, 0x624bd952U, 0x81056813U, 0x3a90104fU, 
+0x7f03d1f8U, 0x6b524472U, 0x1cd53e89U, 0x239ac069U, 
+0x1451958aU, 0xe6915feeU, 0x05dfeeafU, 0x7079f812U, 
+0x3ed2c8c3U, 0xd739bec7U, 0xe8764027U, 0x1d4808aaU, 
+0x6acf7251U, 0x20269a0cU, 0x4eab30d1U, 0x51c2543dU, 
+0x34770f86U, 0x8ba0af56U, 0xfc27d5adU, 0x3f4ffee0U, 
+0xb9b4141aU, 0xb28ce57cU, 0xc72af3c1U, 0x58dbc91dU, 
+0x63d6ef71U, 0x563cd6d4U, 0x0d5b45acU, 0xf53e488dU, 
+0x12322140U, 0xf0e1a622U, 0xff9b8fc8U, 0xd843972dU, 
+0x15cca3a9U, 0x64286d98U, 0x6d31f0b8U, 0xec3498abU, 
+0x69732834U, 0xe16fdd07U, 0xc3682b4dU, 0x8766dcd9U, 
+0x365663c0U, 0xda62fb6bU, 0xbb95785cU, 0x0ee71fc9U, 
+0xb5726795U, 0x37cb55e3U, 0xf35dfc47U, 0x1670f9ccU, 
+0x1ab68a43U, 0x8981c310U, 0x71e4ce31U, 0x3b0d266cU, 
+0x6cacc69bU, 0x80985e30U, 0x84da86bcU, 0x426d435eU, 
+0x1f6964ecU, 0xfe06b9ebU, 0x0884ab03U, 0xfdbae38eU, 
+0xb311d35fU, 0x00000000U, 0x440ef794U, 0x86fbeafaU, 
+0x21bbac2fU, 0xf8650d21U, 0xcfae58c2U, 0xab86355aU, 
+0xa5612a93U, 0x1ef452cfU, 0xfa446167U, 0x77877afbU, 
+0x3cf3a485U, 0xa9a7591cU, 0x2d7ddfa0U, 0x72589454U, 
+0xdd9c7982U, 0x27d818e5U, 0xce336ee1U, 0x2207f64aU, 
+0x0aa5c745U, 0x55808cb1U, 0xc6b7c5e2U, 0xb4ef51b6U, 
+0x4f3606f2U, 0xdbffcd48U, 0x4955b238U, 0xbc6bfab5U, 
+0xe34eb141U, 0x118e7b25U, 0x606ab514U, 0x78fd5311U, 
+0xd518d281U, 0xe2d38762U, 0xe0f2eb24U, 0xebca1a42U, 
+0x7adc3f57U, 0xef88c2ceU, 0x6e8daaddU, 0xa3029e59U, 
+0x09199d20U, 0xe4b033a8U, 0x660901deU, 0xe70c69cdU, 
+0x980fb835U, 0x61f78337U, 0xbdf6cc96U, 0xac78b7b3U, 
+0x977591dfU, 0xc149470bU, 0xade58190U, 0x1897e605U, 
+0xbfd7a0d0U, 0xbe4a96f3U, 0xa29fa87aU, 0x4ae9e85dU, 
+0xc50b9f87U, 0x26452ec6U, 0x03bc5a65U, 0xfbd95744U, 
+0x5c991191U, 0xc496a9a4U, 0x5946ff3eU, 0x404c2f18U, 
+0x679437fdU, 0x53e3387bU, 0x8a3d9975U, 0xd0c73c2eU, 
+0x392c4a2aU, 0x5f254bf4U, 0xa123f21fU, 0x761a4cd8U, 
+0x9dd0569aU, 0x5eb87dd7U, 0x541dba92U, 0x0b38f166U, 
+0x28a2310fU, 0x8c5e2dbfU, 0x8547b09fU, 0x3214bb4cU, 
+0xeda9ae88U, 0xc850da2bU, 0x83240455U, 0xe9eb7604U, 
+0x65b55bbbU, 0x2b1e6b6aU, 0xf68212e8U, 0x9ff13adcU, 
+0xf2c0ca64U, 0xba084e7fU, 0xf4a37eaeU, 0x3035d70aU, 
+0x17edcfefU, 0x2ce0e983U, 0xb130bf19U, 0x7e9ee7dbU, 
+0x96e8a7fcU, 0x4593c1b7U, 0xa4fc1cb0U, 0x47b2adf1U, 
+0x6f109cfeU, 0xb0ad893aU, 0x13af1763U, 0x9a2ed473U, 
+0x3d6e92a6U, 0x019d3623U, 0xf9f83b02U, 0x0cc6738fU, 
+0x2ec185c5U, 0x48c8841bU, 0x5b679378U, 0x92aa7f70U, 
+0x7b410974U, 0x8dc31b9cU, 0xca71b66dU, 0x908b1336U, 
+0x41d1193bU, 0x9554fd99U, 0xafc4edd6U, 0x527e0e58U, 
+0x743b209eU, 0x4c8a5c97U, 0x43f0757dU, 0xae59dbf5U, 
+0xb6ce3df0U, 0xb7530bd3U, 0x190ad026U, 0xb8292239U, 
+};
+static const u32 Te2[256] = {
+0x509bb3e2U, 0xca0663b4U, 0xa2d485e4U, 0x4602216cU, 
+0x3fa83a6fU, 0xbd75a616U, 0x0610134dU, 0xb99c4d60U, 
+0xb44d176aU, 0xf98e7f41U, 0xda8fe277U, 0x08c9cdecU, 
+0x0dd15a0aU, 0x79aa1b03U, 0x4bd37b66U, 0xf757a1e0U, 
+0x5b5afaa5U, 0xa535ea39U, 0x7773c5a2U, 0x0938b17cU, 
+0xe7de2023U, 0x28c0d471U, 0x01f17c90U, 0xbe7d22bdU, 
+0x4ecbec80U, 0x7682b932U, 0xc4dfbd15U, 0xba94c9cbU, 
+0xe4d6a488U, 0xa1dc014fU, 0x32796065U, 0xe907fe82U, 
+0x7e4b74deU, 0x2931a8e1U, 0xb25d0427U, 0x68d2e650U, 
+0x6f33898dU, 0x1699928eU, 0xa7cc1202U, 0xea0f7a29U, 
+0xcbf71f24U, 0x80246442U, 0xf6a6dd70U, 0x3ca0bec4U, 
+0x8be52d05U, 0xedee15f4U, 0x61ea572cU, 0x33881cf5U, 
+0xa325f974U, 0xd5a74046U, 0x601b2bbcU, 0x0ed9dea1U, 
+0x8c0442d8U, 0x84cd8f34U, 0x1e505f62U, 0x492a835dU, 
+0x6ec2f51dU, 0xd2462f9bU, 0x9d7cbf8bU, 0x1768ee1eU, 
+0xff9e6c0cU, 0x15911625U, 0x53933749U, 0xe62f5cb3U, 
+0x2c293f07U, 0x52624bd9U, 0x13810568U, 0x4f3a9010U, 
+0xf87f03d1U, 0x726b5244U, 0x891cd53eU, 0x69239ac0U, 
+0x8a145195U, 0xeee6915fU, 0xaf05dfeeU, 0x127079f8U, 
+0xc33ed2c8U, 0xc7d739beU, 0x27e87640U, 0xaa1d4808U, 
+0x516acf72U, 0x0c20269aU, 0xd14eab30U, 0x3d51c254U, 
+0x8634770fU, 0x568ba0afU, 0xadfc27d5U, 0xe03f4ffeU, 
+0x1ab9b414U, 0x7cb28ce5U, 0xc1c72af3U, 0x1d58dbc9U, 
+0x7163d6efU, 0xd4563cd6U, 0xac0d5b45U, 0x8df53e48U, 
+0x40123221U, 0x22f0e1a6U, 0xc8ff9b8fU, 0x2dd84397U, 
+0xa915cca3U, 0x9864286dU, 0xb86d31f0U, 0xabec3498U, 
+0x34697328U, 0x07e16fddU, 0x4dc3682bU, 0xd98766dcU, 
+0xc0365663U, 0x6bda62fbU, 0x5cbb9578U, 0xc90ee71fU, 
+0x95b57267U, 0xe337cb55U, 0x47f35dfcU, 0xcc1670f9U, 
+0x431ab68aU, 0x108981c3U, 0x3171e4ceU, 0x6c3b0d26U, 
+0x9b6cacc6U, 0x3080985eU, 0xbc84da86U, 0x5e426d43U, 
+0xec1f6964U, 0xebfe06b9U, 0x030884abU, 0x8efdbae3U, 
+0x5fb311d3U, 0x00000000U, 0x94440ef7U, 0xfa86fbeaU, 
+0x2f21bbacU, 0x21f8650dU, 0xc2cfae58U, 0x5aab8635U, 
+0x93a5612aU, 0xcf1ef452U, 0x67fa4461U, 0xfb77877aU, 
+0x853cf3a4U, 0x1ca9a759U, 0xa02d7ddfU, 0x54725894U, 
+0x82dd9c79U, 0xe527d818U, 0xe1ce336eU, 0x4a2207f6U, 
+0x450aa5c7U, 0xb155808cU, 0xe2c6b7c5U, 0xb6b4ef51U, 
+0xf24f3606U, 0x48dbffcdU, 0x384955b2U, 0xb5bc6bfaU, 
+0x41e34eb1U, 0x25118e7bU, 0x14606ab5U, 0x1178fd53U, 
+0x81d518d2U, 0x62e2d387U, 0x24e0f2ebU, 0x42ebca1aU, 
+0x577adc3fU, 0xceef88c2U, 0xdd6e8daaU, 0x59a3029eU, 
+0x2009199dU, 0xa8e4b033U, 0xde660901U, 0xcde70c69U, 
+0x35980fb8U, 0x3761f783U, 0x96bdf6ccU, 0xb3ac78b7U, 
+0xdf977591U, 0x0bc14947U, 0x90ade581U, 0x051897e6U, 
+0xd0bfd7a0U, 0xf3be4a96U, 0x7aa29fa8U, 0x5d4ae9e8U, 
+0x87c50b9fU, 0xc626452eU, 0x6503bc5aU, 0x44fbd957U, 
+0x915c9911U, 0xa4c496a9U, 0x3e5946ffU, 0x18404c2fU, 
+0xfd679437U, 0x7b53e338U, 0x758a3d99U, 0x2ed0c73cU, 
+0x2a392c4aU, 0xf45f254bU, 0x1fa123f2U, 0xd8761a4cU, 
+0x9a9dd056U, 0xd75eb87dU, 0x92541dbaU, 0x660b38f1U, 
+0x0f28a231U, 0xbf8c5e2dU, 0x9f8547b0U, 0x4c3214bbU, 
+0x88eda9aeU, 0x2bc850daU, 0x55832404U, 0x04e9eb76U, 
+0xbb65b55bU, 0x6a2b1e6bU, 0xe8f68212U, 0xdc9ff13aU, 
+0x64f2c0caU, 0x7fba084eU, 0xaef4a37eU, 0x0a3035d7U, 
+0xef17edcfU, 0x832ce0e9U, 0x19b130bfU, 0xdb7e9ee7U, 
+0xfc96e8a7U, 0xb74593c1U, 0xb0a4fc1cU, 0xf147b2adU, 
+0xfe6f109cU, 0x3ab0ad89U, 0x6313af17U, 0x739a2ed4U, 
+0xa63d6e92U, 0x23019d36U, 0x02f9f83bU, 0x8f0cc673U, 
+0xc52ec185U, 0x1b48c884U, 0x785b6793U, 0x7092aa7fU, 
+0x747b4109U, 0x9c8dc31bU, 0x6dca71b6U, 0x36908b13U, 
+0x3b41d119U, 0x999554fdU, 0xd6afc4edU, 0x58527e0eU, 
+0x9e743b20U, 0x974c8a5cU, 0x7d43f075U, 0xf5ae59dbU, 
+0xf0b6ce3dU, 0xd3b7530bU, 0x26190ad0U, 0x39b82922U, 
+};
+static const u32 Te3[256] = {
+0xe2509bb3U, 0xb4ca0663U, 0xe4a2d485U, 0x6c460221U, 
+0x6f3fa83aU, 0x16bd75a6U, 0x4d061013U, 0x60b99c4dU, 
+0x6ab44d17U, 0x41f98e7fU, 0x77da8fe2U, 0xec08c9cdU, 
+0x0a0dd15aU, 0x0379aa1bU, 0x664bd37bU, 0xe0f757a1U, 
+0xa55b5afaU, 0x39a535eaU, 0xa27773c5U, 0x7c0938b1U, 
+0x23e7de20U, 0x7128c0d4U, 0x9001f17cU, 0xbdbe7d22U, 
+0x804ecbecU, 0x327682b9U, 0x15c4dfbdU, 0xcbba94c9U, 
+0x88e4d6a4U, 0x4fa1dc01U, 0x65327960U, 0x82e907feU, 
+0xde7e4b74U, 0xe12931a8U, 0x27b25d04U, 0x5068d2e6U, 
+0x8d6f3389U, 0x8e169992U, 0x02a7cc12U, 0x29ea0f7aU, 
+0x24cbf71fU, 0x42802464U, 0x70f6a6ddU, 0xc43ca0beU, 
+0x058be52dU, 0xf4edee15U, 0x2c61ea57U, 0xf533881cU, 
+0x74a325f9U, 0x46d5a740U, 0xbc601b2bU, 0xa10ed9deU, 
+0xd88c0442U, 0x3484cd8fU, 0x621e505fU, 0x5d492a83U, 
+0x1d6ec2f5U, 0x9bd2462fU, 0x8b9d7cbfU, 0x1e1768eeU, 
+0x0cff9e6cU, 0x25159116U, 0x49539337U, 0xb3e62f5cU, 
+0x072c293fU, 0xd952624bU, 0x68138105U, 0x104f3a90U, 
+0xd1f87f03U, 0x44726b52U, 0x3e891cd5U, 0xc069239aU, 
+0x958a1451U, 0x5feee691U, 0xeeaf05dfU, 0xf8127079U, 
+0xc8c33ed2U, 0xbec7d739U, 0x4027e876U, 0x08aa1d48U, 
+0x72516acfU, 0x9a0c2026U, 0x30d14eabU, 0x543d51c2U, 
+0x0f863477U, 0xaf568ba0U, 0xd5adfc27U, 0xfee03f4fU, 
+0x141ab9b4U, 0xe57cb28cU, 0xf3c1c72aU, 0xc91d58dbU, 
+0xef7163d6U, 0xd6d4563cU, 0x45ac0d5bU, 0x488df53eU, 
+0x21401232U, 0xa622f0e1U, 0x8fc8ff9bU, 0x972dd843U, 
+0xa3a915ccU, 0x6d986428U, 0xf0b86d31U, 0x98abec34U, 
+0x28346973U, 0xdd07e16fU, 0x2b4dc368U, 0xdcd98766U, 
+0x63c03656U, 0xfb6bda62U, 0x785cbb95U, 0x1fc90ee7U, 
+0x6795b572U, 0x55e337cbU, 0xfc47f35dU, 0xf9cc1670U, 
+0x8a431ab6U, 0xc3108981U, 0xce3171e4U, 0x266c3b0dU, 
+0xc69b6cacU, 0x5e308098U, 0x86bc84daU, 0x435e426dU, 
+0x64ec1f69U, 0xb9ebfe06U, 0xab030884U, 0xe38efdbaU, 
+0xd35fb311U, 0x00000000U, 0xf794440eU, 0xeafa86fbU, 
+0xac2f21bbU, 0x0d21f865U, 0x58c2cfaeU, 0x355aab86U, 
+0x2a93a561U, 0x52cf1ef4U, 0x6167fa44U, 0x7afb7787U, 
+0xa4853cf3U, 0x591ca9a7U, 0xdfa02d7dU, 0x94547258U, 
+0x7982dd9cU, 0x18e527d8U, 0x6ee1ce33U, 0xf64a2207U, 
+0xc7450aa5U, 0x8cb15580U, 0xc5e2c6b7U, 0x51b6b4efU, 
+0x06f24f36U, 0xcd48dbffU, 0xb2384955U, 0xfab5bc6bU, 
+0xb141e34eU, 0x7b25118eU, 0xb514606aU, 0x531178fdU, 
+0xd281d518U, 0x8762e2d3U, 0xeb24e0f2U, 0x1a42ebcaU, 
+0x3f577adcU, 0xc2ceef88U, 0xaadd6e8dU, 0x9e59a302U, 
+0x9d200919U, 0x33a8e4b0U, 0x01de6609U, 0x69cde70cU, 
+0xb835980fU, 0x833761f7U, 0xcc96bdf6U, 0xb7b3ac78U, 
+0x91df9775U, 0x470bc149U, 0x8190ade5U, 0xe6051897U, 
+0xa0d0bfd7U, 0x96f3be4aU, 0xa87aa29fU, 0xe85d4ae9U, 
+0x9f87c50bU, 0x2ec62645U, 0x5a6503bcU, 0x5744fbd9U, 
+0x11915c99U, 0xa9a4c496U, 0xff3e5946U, 0x2f18404cU, 
+0x37fd6794U, 0x387b53e3U, 0x99758a3dU, 0x3c2ed0c7U, 
+0x4a2a392cU, 0x4bf45f25U, 0xf21fa123U, 0x4cd8761aU, 
+0x569a9dd0U, 0x7dd75eb8U, 0xba92541dU, 0xf1660b38U, 
+0x310f28a2U, 0x2dbf8c5eU, 0xb09f8547U, 0xbb4c3214U, 
+0xae88eda9U, 0xda2bc850U, 0x04558324U, 0x7604e9ebU, 
+0x5bbb65b5U, 0x6b6a2b1eU, 0x12e8f682U, 0x3adc9ff1U, 
+0xca64f2c0U, 0x4e7fba08U, 0x7eaef4a3U, 0xd70a3035U, 
+0xcfef17edU, 0xe9832ce0U, 0xbf19b130U, 0xe7db7e9eU, 
+0xa7fc96e8U, 0xc1b74593U, 0x1cb0a4fcU, 0xadf147b2U, 
+0x9cfe6f10U, 0x893ab0adU, 0x176313afU, 0xd4739a2eU, 
+0x92a63d6eU, 0x3623019dU, 0x3b02f9f8U, 0x738f0cc6U, 
+0x85c52ec1U, 0x841b48c8U, 0x93785b67U, 0x7f7092aaU, 
+0x09747b41U, 0x1b9c8dc3U, 0xb66dca71U, 0x1336908bU, 
+0x193b41d1U, 0xfd999554U, 0xedd6afc4U, 0x0e58527eU, 
+0x209e743bU, 0x5c974c8aU, 0x757d43f0U, 0xdbf5ae59U, 
+0x3df0b6ceU, 0x0bd3b753U, 0xd026190aU, 0x2239b829U, 
+};
+static const u32 Te4[256] = {
+0x18181818U, 0x23232323U, 0xc6c6c6c6U, 0xe8e8e8e8U, 
+0x87878787U, 0xb8b8b8b8U, 0x01010101U, 0x4f4f4f4fU, 
+0x36363636U, 0xa6a6a6a6U, 0xd2d2d2d2U, 0xf5f5f5f5U, 
+0x79797979U, 0x6f6f6f6fU, 0x91919191U, 0x52525252U, 
+0x60606060U, 0xbcbcbcbcU, 0x9b9b9b9bU, 0x8e8e8e8eU, 
+0xa3a3a3a3U, 0x0c0c0c0cU, 0x7b7b7b7bU, 0x35353535U, 
+0x1d1d1d1dU, 0xe0e0e0e0U, 0xd7d7d7d7U, 0xc2c2c2c2U, 
+0x2e2e2e2eU, 0x4b4b4b4bU, 0xfefefefeU, 0x57575757U, 
+0x15151515U, 0x77777777U, 0x37373737U, 0xe5e5e5e5U, 
+0x9f9f9f9fU, 0xf0f0f0f0U, 0x4a4a4a4aU, 0xdadadadaU, 
+0x58585858U, 0xc9c9c9c9U, 0x29292929U, 0x0a0a0a0aU, 
+0xb1b1b1b1U, 0xa0a0a0a0U, 0x6b6b6b6bU, 0x85858585U, 
+0xbdbdbdbdU, 0x5d5d5d5dU, 0x10101010U, 0xf4f4f4f4U, 
+0xcbcbcbcbU, 0x3e3e3e3eU, 0x05050505U, 0x67676767U, 
+0xe4e4e4e4U, 0x27272727U, 0x41414141U, 0x8b8b8b8bU, 
+0xa7a7a7a7U, 0x7d7d7d7dU, 0x95959595U, 0xd8d8d8d8U, 
+0xfbfbfbfbU, 0xeeeeeeeeU, 0x7c7c7c7cU, 0x66666666U, 
+0xddddddddU, 0x17171717U, 0x47474747U, 0x9e9e9e9eU, 
+0xcacacacaU, 0x2d2d2d2dU, 0xbfbfbfbfU, 0x07070707U, 
+0xadadadadU, 0x5a5a5a5aU, 0x83838383U, 0x33333333U, 
+0x63636363U, 0x02020202U, 0xaaaaaaaaU, 0x71717171U, 
+0xc8c8c8c8U, 0x19191919U, 0x49494949U, 0xd9d9d9d9U, 
+0xf2f2f2f2U, 0xe3e3e3e3U, 0x5b5b5b5bU, 0x88888888U, 
+0x9a9a9a9aU, 0x26262626U, 0x32323232U, 0xb0b0b0b0U, 
+0xe9e9e9e9U, 0x0f0f0f0fU, 0xd5d5d5d5U, 0x80808080U, 
+0xbebebebeU, 0xcdcdcdcdU, 0x34343434U, 0x48484848U, 
+0xffffffffU, 0x7a7a7a7aU, 0x90909090U, 0x5f5f5f5fU, 
+0x20202020U, 0x68686868U, 0x1a1a1a1aU, 0xaeaeaeaeU, 
+0xb4b4b4b4U, 0x54545454U, 0x93939393U, 0x22222222U, 
+0x64646464U, 0xf1f1f1f1U, 0x73737373U, 0x12121212U, 
+0x40404040U, 0x08080808U, 0xc3c3c3c3U, 0xececececU, 
+0xdbdbdbdbU, 0xa1a1a1a1U, 0x8d8d8d8dU, 0x3d3d3d3dU, 
+0x97979797U, 0x00000000U, 0xcfcfcfcfU, 0x2b2b2b2bU, 
+0x76767676U, 0x82828282U, 0xd6d6d6d6U, 0x1b1b1b1bU, 
+0xb5b5b5b5U, 0xafafafafU, 0x6a6a6a6aU, 0x50505050U, 
+0x45454545U, 0xf3f3f3f3U, 0x30303030U, 0xefefefefU, 
+0x3f3f3f3fU, 0x55555555U, 0xa2a2a2a2U, 0xeaeaeaeaU, 
+0x65656565U, 0xbabababaU, 0x2f2f2f2fU, 0xc0c0c0c0U, 
+0xdedededeU, 0x1c1c1c1cU, 0xfdfdfdfdU, 0x4d4d4d4dU, 
+0x92929292U, 0x75757575U, 0x06060606U, 0x8a8a8a8aU, 
+0xb2b2b2b2U, 0xe6e6e6e6U, 0x0e0e0e0eU, 0x1f1f1f1fU, 
+0x62626262U, 0xd4d4d4d4U, 0xa8a8a8a8U, 0x96969696U, 
+0xf9f9f9f9U, 0xc5c5c5c5U, 0x25252525U, 0x59595959U, 
+0x84848484U, 0x72727272U, 0x39393939U, 0x4c4c4c4cU, 
+0x5e5e5e5eU, 0x78787878U, 0x38383838U, 0x8c8c8c8cU, 
+0xd1d1d1d1U, 0xa5a5a5a5U, 0xe2e2e2e2U, 0x61616161U, 
+0xb3b3b3b3U, 0x21212121U, 0x9c9c9c9cU, 0x1e1e1e1eU, 
+0x43434343U, 0xc7c7c7c7U, 0xfcfcfcfcU, 0x04040404U, 
+0x51515151U, 0x99999999U, 0x6d6d6d6dU, 0x0d0d0d0dU, 
+0xfafafafaU, 0xdfdfdfdfU, 0x7e7e7e7eU, 0x24242424U, 
+0x3b3b3b3bU, 0xababababU, 0xcecececeU, 0x11111111U, 
+0x8f8f8f8fU, 0x4e4e4e4eU, 0xb7b7b7b7U, 0xebebebebU, 
+0x3c3c3c3cU, 0x81818181U, 0x94949494U, 0xf7f7f7f7U, 
+0xb9b9b9b9U, 0x13131313U, 0x2c2c2c2cU, 0xd3d3d3d3U, 
+0xe7e7e7e7U, 0x6e6e6e6eU, 0xc4c4c4c4U, 0x03030303U, 
+0x56565656U, 0x44444444U, 0x7f7f7f7fU, 0xa9a9a9a9U, 
+0x2a2a2a2aU, 0xbbbbbbbbU, 0xc1c1c1c1U, 0x53535353U, 
+0xdcdcdcdcU, 0x0b0b0b0bU, 0x9d9d9d9dU, 0x6c6c6c6cU, 
+0x31313131U, 0x74747474U, 0xf6f6f6f6U, 0x46464646U, 
+0xacacacacU, 0x89898989U, 0x14141414U, 0xe1e1e1e1U, 
+0x16161616U, 0x3a3a3a3aU, 0x69696969U, 0x09090909U, 
+0x70707070U, 0xb6b6b6b6U, 0xd0d0d0d0U, 0xededededU, 
+0xccccccccU, 0x42424242U, 0x98989898U, 0xa4a4a4a4U, 
+0x28282828U, 0x5c5c5c5cU, 0xf8f8f8f8U, 0x86868686U, 
+};
+
 #endif  /* FC__RAND_H */
diff -urw freeciv-1.14.0/common/tech.c freeciv/common/tech.c
--- freeciv-1.14.0/common/tech.c	2002-10-11 19:35:13.000000000 -0400
+++ freeciv/common/tech.c	2003-04-02 18:27:05.000000000 -0500
@@ -462,6 +462,12 @@
     cost = 1;
   }
 
+  /* For casual players, the AI gets tech far too fast.  This
+     slows down how fast the AI gets tech by 4x at the easy level */
+  if (!game.is_new_game && pplayer->ai.control) {
+      cost *= game.slowai_tech;
+  }
+
   return cost;
 }
 
Only in freeciv/server: DIFF
diff -urw freeciv-1.14.0/server/gamehand.c freeciv/server/gamehand.c
--- freeciv-1.14.0/server/gamehand.c	2002-10-11 19:35:50.000000000 -0400
+++ freeciv/server/gamehand.c	2003-04-02 18:31:15.000000000 -0500
@@ -42,9 +42,77 @@
   int start_pos[MAX_NUM_PLAYERS]; /* indices into map.start_positions[] */
 
   if (!map.fixed_start_positions) {
-    /* except in a scenario which provides them,
-       shuffle the start positions around... */
     assert(game.nplayers==map.num_start_positions);
+
+    /* We move all of the ai players after all of the humans.  This is done
+       in conjunciton with code in mapgen.c which makes sure all of the
+       starting points on good islands come before (in the 
+       map.start_positions array) all of the starting positions on bad
+       islands. 
+
+       The code assumes that each player gets their own island.
+       If not, then what this code will do is cause all of the humans
+       to share the best islands and all of the AIs to share the not-so-good
+       islands.
+
+       Note that this is an inefficient O(N^2) algorithm; with the current
+       max of 30 players, there should not be a problem */
+
+  if (game.best_isles) {
+    int last_human_player = game.nplayers + 1;
+    int first_ai_player;
+
+    for(j=game.nplayers - 1; j >=0; j--) {
+        if(!game.players[j].ai.control) {
+	    last_human_player = j;
+	    break;
+	    }
+        }
+    if(last_human_player + 1< game.nplayers) {
+      for(i=0; i<last_human_player; i++) {
+        if(game.players[i].ai.control) { 
+	    /* Swap the positions */
+            x=map.start_positions[last_human_player].x;
+            y=map.start_positions[last_human_player].y;
+            map.start_positions[last_human_player].x=map.start_positions[i].x;
+            map.start_positions[last_human_player].y=map.start_positions[i].y;
+            map.start_positions[i].x=x;
+            map.start_positions[i].y=y;
+            for(j=game.nplayers - 1; j >=0 ; j--) {
+                if(!game.players[j].ai.control) {
+	            last_human_player = j;
+		    break;
+	            }
+                }
+	    }
+        }
+    }
+
+    /* except in a scenario which provides them,
+       shuffle the human's start positions around... */
+    for (i=0; i<= last_human_player;i++) { /* no advantage to the romans!! */
+      j=myrand(last_human_player + 1);
+      x=map.start_positions[j].x;
+      y=map.start_positions[j].y;
+      map.start_positions[j].x=map.start_positions[i].x;
+      map.start_positions[j].y=map.start_positions[i].y;
+      map.start_positions[i].x=x;
+      map.start_positions[i].y=y;
+    }
+
+    /* Also shuffle all of the ai's start positions */
+    first_ai_player = last_human_player + 1;
+    for(i = first_ai_player;i < game.nplayers; i++) { 
+        j = myrand(game.nplayers - first_ai_player);
+	j += first_ai_player;
+        x=map.start_positions[j].x;
+        y=map.start_positions[j].y;
+        map.start_positions[j].x=map.start_positions[i].x;
+        map.start_positions[j].y=map.start_positions[i].y;
+        map.start_positions[i].x=x;
+        map.start_positions[i].y=y;
+    }
+  } else /* ! game.best_isles */ {
     for (i=0; i<game.nplayers;i++) { /* no advantage to the romans!! */
       j=myrand(game.nplayers);
       x=map.start_positions[j].x;
@@ -54,6 +122,8 @@
       map.start_positions[i].x=x;
       map.start_positions[i].y=y;
     }
+  } /* game.best_isles */
+    
     for(i=0; i<game.nplayers; i++) {
       start_pos[i] = i;
     } 
diff -urw freeciv-1.14.0/server/mapgen.c freeciv/server/mapgen.c
--- freeciv-1.14.0/server/mapgen.c	2002-10-11 19:35:50.000000000 -0400
+++ freeciv/server/mapgen.c	2003-04-04 16:25:10.000000000 -0500
@@ -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"
@@ -41,6 +42,8 @@
 static void mapgenerator3(void);
 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);
 
@@ -258,13 +261,23 @@
   while (i > 0 && j < 500) {
     j++;
 
+    if(map.ysize >= 18) {
     y=myrand(map.ysize*10/180)+map.ysize*110/180;
+        }
+    else {
+        y = map.ysize*110/180;
+	}
     x=myrand(map.xsize);
     if (map_get_terrain(x, y)==T_GRASSLAND) {
       make_desert(x,y, hmap(x, y), 50);
       i--;
     }
+    if(map.ysize >= 18) {
     y=myrand(map.ysize*10/180)+map.ysize*60/180;
+        }
+    else {
+        y = map.ysize*60/180;
+	}
     x=myrand(map.xsize);
     if (map_get_terrain(x, y)==T_GRASSLAND) {
       make_desert(x,y, hmap(x, y), 50);
@@ -823,7 +836,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;
@@ -846,7 +859,7 @@
     else
       tres*=9;
     tres/=10;
-  } while (abs(total-count)> maxval/40);
+  } while (abs(total-count)> window_size/40);
   if (map.separatepoles) {
     make_passable();
   }
@@ -941,8 +954,9 @@
  Allocate islands array and fill in values.
  Note this is only use for map.generator<=1, since others
  setups islands and starters explicitly.
+ Output: The number of good islands that this map has
 **************************************************************************/
-static void setup_isledata(void)
+int setup_isledata(void)
 {
   int x;
   int good, mingood, maxgood;
@@ -1102,8 +1116,31 @@
 	      _("Map generator: not enough start positions, fixing."));
     }
   }
-  freelog(LOG_DEBUG, "The map has %i starting positions on %i isles.",
+  freelog(LOG_VERBOSE, "The map has %i starting positions on %i isles.",
 	  starters, goodisles);
+  return goodisles;
+}
+
+/**************************************************************************
+ Comparison function that compares the goodness of two start points (how
+ good the island the two start points are on
+ *************************************************************************/
+
+static int
+compar_isle_goodness(const void *a,const void *b) 
+{
+   int ia, ib;
+   int x,y;
+   struct map_position *t;
+   t = (struct map_position *)a;
+   x=t->x;
+   y=t->y;
+   ia = islands[(int)map_get_continent(x, y)].goodies;
+   t = (struct map_position *)b;
+   x=t->x;
+   y=t->y;
+   ib = islands[(int)map_get_continent(x, y)].goodies;
+   return ib - ia;
 }
 
 /**************************************************************************
@@ -1113,23 +1150,106 @@
   FIXME: MAXTRIES used to be 1.000.000, but has been raised to 10.000.000
          because a set of values hit the limit. At some point we want to
          make a better solution.
+  Output: Whether this is a good map; 1 if yes, 0 if no
 **************************************************************************/
 #define MAXTRIES 10000000
-void create_start_positions(void)
+int Tec_Cleanup(void);
+
+int
+create_start_positions(void)
 {
   int nr=0;
   int dist=40;
-  int x, y, j=0, k, sum;
+  int x, y, i, j=0, k, sum;
   int counter = 0;
+  int isles = 0;
+  int xz, yz, pxz;
+
 
   if (!islands)		/* already setup for generators 2,3, and 4 */
-    setup_isledata();
+    isles = setup_isledata();
+  else
+    isles = 10000; /* Big number so this passes the "own island" test */
+
+  yz = map.ysize - 2;
+  xz = pxz = map.xsize;
+
+  for(x=0;x<map.xsize;x++) {
+       for(y=1;y<map.ysize - 1;y++) {
+           if(map_get_terrain(x, y) != T_OCEAN) {
+               xz--;
+               break;
+               }
+           }
+       }
+
+  for(x=0;x<map.xsize;x++) {
+       for(y=2;y<map.ysize - 2;y++) {
+           if(map_get_terrain(x, y) != T_OCEAN) {
+               pxz--;
+               break;
+               }
+           }
+       }
+
+  for(y=0;y<map.ysize;y++) {
+       for(x=0;x<map.ysize;x++) {
+           if(map_get_terrain(x, y) != T_OCEAN) {
+               yz--;
+               break;
+               }
+           }
+       }
+
+  printf("seed: %d islands: %d good: %d xz: %d pxz: %d yz: %d ",map.seed,
+         map.num_continents,isles,xz,pxz,yz);
+
+  for(i=1; i<=map.num_continents; i++) {
+      printf("(%d %d) ",i,islands[i].goodies);
+      }
+  printf("\n");
+
+  if (!game.check_isles)
+      isles = 0;
+
+  if(isles < game.check_isles) {
+      if(map.generator > 6) {
+          Tec_Cleanup();
+      }
+//      map.seed++; 
+      map.seed = myrand(MAX_UINT32); 
+      free(islands);
+      free(height_map);
+      free(river_map);
+      islands = NULL;
+      height_map = NULL;
+      river_map = NULL;
+      maxval = 0;
+      forests = 0;
+      free(map.tiles);
+      map.tiles = NULL;
+      map.num_continents = 0;
+      map.num_start_positions = 0;
+      map.have_specials = FALSE;
+      map.have_huts = FALSE;
+      /* Initializing the next two may not be necessary */
+      map.fixed_start_positions = FALSE;
+      map.have_rivers_overlay = FALSE;
+      return 0;
+  }
+
+  printf("Using seed %d\n",map.seed);
 
   if(dist>= map.xsize/2)
     dist= map.xsize/2;
   if(dist>= map.ysize/2)
     dist= map.ysize/2;
 
+  /* If we make distance really big here (and do the check to make sure each
+     player gets their own island), we can 100% ensure that each player
+     gets their own island; dist is the minimum distance that two players
+     can be from one another on the same island */
+
   sum=0;
   for (k=0; k<=map.num_continents; k++) {
     sum += islands[k].starters;
@@ -1167,8 +1287,21 @@
   }
   map.num_start_positions = game.nplayers;
 
+  /* Sort the array so that the lowered numbered starting positions are
+     always on the best isles; this is used in conjunction with code in
+     gamehand.c to make sure that the humans get the best islands; the
+     code works best when each player gets their own island (otherwise
+     all of the humans will share the best islands and all of the AIs will
+     share the worse islands) */
+
+  if (game.best_isles) {
+      qsort(map.start_positions,map.num_start_positions,
+	  sizeof(struct map_position),compar_isle_goodness);
+  }
+
   free(islands);
   islands = NULL;
+  return 1; /* Good map */
 }
 
 /**************************************************************************
@@ -1196,6 +1329,10 @@
     map_allocate();
     /* if one mapgenerator fails, it will choose another mapgenerator */
     /* 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 )
@@ -1245,7 +1382,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 > 6){
     /*map.riverlength*= 10; */
     /*I leave this out, people will get too upset 
       if they have to change all their scripts */
@@ -1289,7 +1426,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)
@@ -1338,7 +1475,866 @@
   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 */
+  if (game.nplayers > 5) /* # of plates which are continental */
+      tectonic.ncontinents = game.nplayers;
+  else
+      tectonic.ncontinents = 5;
+  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 */
+
+/*
+ * ---------- Declarations ------------------------------------------------------
+ */
+int Wrap_x(register int val);
+int Wrap_y(register int val);
+Rock_t * AllocRock(Plate_t *pl);
+int SeedPlates(void);
+int InitSurface(void);
+int SeedHotSpots(void);
+int Epoch(void);
+int AssignDirections(void);
+int SetMovementVectors(int iter);
+int MovePlates(void);
+int MountainBuild(void);
+int Rift(int x, int y);
+int Fold(int x, int y);
+int ElevNearby(int x, int y, Rock_t *rp, short height);
+int Subsume(int x, int y);
+int EruptHotSpots(void);
+int Erode(void);
+
+/*
+ * ---------- Utilities ------------------------------------------------------
+ */
+/*
+ * Wraparound from one side of the world to the other.
+ */
+int Wrap_x(register int val)
+{
+    if (val < 0)
+        val += tectonic.xsize;
+    else if (val >= tectonic.xsize)
+        val -= tectonic.xsize;
+    return (val);
+}
+
+int Wrap_y(register int val)
+{
+    if (val < 0)
+        val += tectonic.ysize;
+    else if (val >= tectonic.ysize)
+        val -= tectonic.ysize;
+    return (val);
+}
+
+/*
+ * Allocate a rock.
+ */
+Rock_t * AllocRock(Plate_t *pl)
+{
+    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(void)
+{
+    register int i;
+    register Plate_t *pl;	/* ptr to plates */
+
+    pl = &plates[0];
+    for (i = 0; i < tectonic.nplates; ++i, ++pl) {
+        pl->dx = myrand(tectonic.xsize);
+        pl->dy = myrand(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(void)
+{
+    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(void)
+{
+    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 = myrand(tectonic.xsize);
+        hsp->y = myrand(tectonic.ysize);
+        hsp->howhot = (myrand(tectonic.hotspotheight) + myrand(tectonic.hotspotheight) +
+          myrand(tectonic.hotspotheight) + myrand(tectonic.hotspotheight) + 2) >> 1;
+    }
+    return 0;
+}
+
+/*
+ * All initialization.
+ */
+int Tec_Init(void)
+{
+    nplates = tectonic.nplates;
+    SeedPlates();
+    InitSurface();
+    SeedHotSpots();
+    return 0;
+}
+
+/* 
+ * Cleanup of memory allocated by tectonic code 
+ */
+int Tec_Cleanup(void)
+{
+    int x,y;
+    Rock_t *tofree,*tmp;
+
+    /* Start up with the freeRockList */
+    tofree = freeRockList;
+    while(tofree != NULL) {
+        tmp = tofree->next;
+        free(tofree);
+        tofree = tmp;
+	}
+    freeRockList = NULL;
+    for (x = 0; x < tectonic.xsize; ++x) {
+        for (y = 0; y < tectonic.ysize; ++y) {
+            tofree = surface[x][y];
+            while(tofree != NULL) {
+	        tmp = tofree->next;
+		free(tofree);
+		tofree = tmp;
+		}
+            surface[x][y] = NULL;
+            }
+       }
+    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(void)
+{
+    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 = myrand(360);
+        dist = (float)(myrand(101) + myrand(101) + myrand(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(int iter)
+{
+    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(void)
+{
+    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(int x, int 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 */
+    Rock_t *tofree, *tmp; /* For freeing memory */
+
+    pl = NULL;
+
+    /*
+     * Find a plate to go with.
+     */
+    for (tries = 0; tries < 30; ++tries) {
+        px = Wrap_x(x + myrand(3) - 1);
+        py = Wrap_y(y + myrand(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!!! */
+    tofree = surface[x][y];
+    while(tofree != NULL) {
+        tmp = tofree->next;
+	free(tofree);
+	tofree = tmp;
+        }
+    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(int x, int 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(int x, int 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 = myrand(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(int x, int 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(void)
+{
+    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(void)
+{
+    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(void)
+{
+    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 = myrand(3) - 2;
+                    j = myrand(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(void)
+{
+    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)
+{
+  register 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) + myrand(2000);
+      }
+
+      /* 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;
 }
@@ -1394,7 +2390,7 @@
     rand_map_pos(&x, &y);
     l=myrand(6);
     if (map_get_terrain(x, y)!=T_OCEAN && 
-	( map_get_terrain(x, y)!=T_ARCTIC || l<3 )
+	( map_get_terrain(x, y)!=T_ARCTIC )
 	) {
       if (!is_hut_close(x,y)) {
 	number--;
@@ -2208,7 +3204,271 @@
   maxval -= minval;
   adjust_map(minval);
   
-  make_land();
+  make_land(maxval);
   free(height_map);
   height_map = NULL;
 }
+
+static int is_ocean(int l)
+{
+  return (l == T_OCEAN);
+}
+
+static int land_terrain(int x, int y)
+{
+  return !is_ocean(map_get_terrain(x,y));
+}
+
+static int border_score(int x, int y)
+{
+  int adj_score = 2;
+  int diag_score = 1;
+  int score = 0;
+  score += land_terrain(x-1,y) ? adj_score : 0;
+  score += land_terrain(x+1,y) ? adj_score : 0;
+  score += land_terrain(x,y-1) ? adj_score : 0;
+  score += land_terrain(x,y+1) ? adj_score : 0;
+  score += land_terrain(x-1,y-1) ? diag_score : 0;
+  score += land_terrain(x+1,y-1) ? diag_score : 0;
+  score += land_terrain(x-1,y+1) ? diag_score : 0;
+  score += land_terrain(x+1,y+1) ? diag_score : 0;
+  return score;
+}
+
+static int random_new_land(int x, int y)
+{
+  int score;
+  int random;
+  if(land_terrain(x, y)) {
+    return T_PLAINS;
+  }
+  score = border_score(x, y);
+  random = myrand(4*2+4*1);
+  return random + 1 > score  ? T_OCEAN : T_GRASSLAND;
+  
+}
+
+/* Creates a peninsula and put the player's starting position
+   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)
+{
+  int cx, cy;
+
+  cx = x+width/2;
+  for(cy = y; cy != y + (height + 1)*direction; 
+      cy += direction) {
+    map_set_terrain(cx, cy, T_GRASSLAND);
+    map_set_continent(cx, cy, 1);
+  }
+  remaining_count -= height; /* account for the already added strip */
+  cy = y;
+  for(cx = x + width/2 - 2; cx <= x + width/2 + 2; cx ++) {
+    map_set_terrain(cx, cy, T_GRASSLAND);
+    map_set_continent(cx, cy, 1);    
+  }
+  remaining_count -= 4; /* account for extra 4 (not 5 because that would 
+			double count the one already done by height strip.*/
+  
+  while (remaining_count > 0) {
+    for(cx = x; cx < x+width; cx++) {
+      for(cy = y; cy != y + (height + 1)*direction; cy += direction) {
+	int new_terrain = random_new_land(cx, cy);
+	if(new_terrain == T_GRASSLAND){
+	  remaining_count--;
+	  map_set_terrain(cx, cy, T_GRASSLAND);
+	  map_set_continent(cx, cy, 1);
+	  hmap(cx, cy) = 20 * (cx - x) * (width - (cx - x)) + myrand(80) - 40;
+	}
+	if(remaining_count <= 0) {
+	  goto done_with_peninsula;
+	}
+      }
+    }
+  }
+
+ done_with_peninsula:
+
+  map.start_positions[player_number].x = x+width/2;
+  map.start_positions[player_number].y = y;
+}
+
+/* This generator creates a map with one penisula for each 
+   player and an isthmus between.  It creates a central
+   ocean and puts the peninsulas around the edges.  It is 
+   intented for quicker games. Should look something like this:
+   *****************************
+   **  *****  *****  *****    ** 
+   *    ***    ***    ***      *
+   *                           *
+   *                           *
+   *    ***    ***             *
+   **  *****  *****           **
+   *****************************
+ */
+static void mapgenerator6(void)
+{
+  int peninsulas = game.nplayers;
+  int peninsulas_on_one_side = (peninsulas + 1)/2;
+  int isthmus_width = 10;
+  int peninsula_separation = 5;
+  int peninsula_width = 
+    (map.xsize - isthmus_width - peninsula_separation)
+      /(peninsulas_on_one_side) - peninsula_separation;
+  /* if landpercent <= 50, then make shorter peninsulas */
+  int peninsula_height = (map.landpercent <= 50) 
+    ? map.ysize/3
+      : (map.ysize*2)/5;
+  int continent_percent = (map.landpercent <= 50) 
+    ? (map.landpercent * 3)/2 
+      : (map.landpercent * 5)/4;
+  int i, x, y;
+  int polar_height = 3;
+  int remaining_count = 
+    MIN(isthmus_width * (map.ysize - polar_height*2),
+	((isthmus_width+peninsula_separation) * (map.ysize - polar_height*2) 
+	 * continent_percent)/100);
+ 
+  height_map = fc_malloc(sizeof(int) * map.xsize * map.ysize);
+
+  /* initialize everything to ocean */
+  for (y = 0 ; y < map.ysize ; y++) 
+    for (x = 0 ; x < map.xsize ; x++) {
+      map_set_terrain(x, y, T_OCEAN);
+      map_set_continent(x, y, 0);
+      hmap(x, y) = 0;
+    }
+
+  /* create polar regions */
+  for (x = 0 ; x < map.xsize; x++) {
+    for (y = 0; y < polar_height; y++) {
+      int rand_num = myrand(9);
+      map_set_terrain(x, y, rand_num > 7 ? T_ARCTIC :
+		      (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+      map_set_continent(x, y, 1);
+      rand_num = myrand(9);
+      map_set_terrain(x, map.ysize-1-y, rand_num > 7 ? T_ARCTIC :
+		      (rand_num < 2 ? T_MOUNTAINS : T_TUNDRA));
+      map_set_continent(x, map.ysize-1-y, 1);
+    }
+  }
+  
+  /* build polar regions road */
+  for (x = 0 ; x < map.xsize; x++) {
+	  y = polar_height-1;
+	  if(map_build_road_time(x,y-1) < map_build_road_time(x,y))
+	  {
+		  map_set_special(x,y-1,S_ROAD);
+	  } else {
+		  map_set_special(x,y,S_ROAD);
+	  }
+	  y = map.ysize-polar_height;
+	  if(map_build_road_time(x,y+1) < map_build_road_time(x,y))
+	  {
+		  map_set_special(x,y+1,S_ROAD);
+	  } else {
+		  map_set_special(x,y,S_ROAD);
+	  }
+  }
+
+  map.num_continents = 1;
+
+  /* create isthmus centeral strip */
+  x = isthmus_width/2;
+  for (y = polar_height; y < map.ysize - polar_height; y++) {
+    map_set_terrain(x, y, T_GRASSLAND);
+    map_set_continent(x, y, 1);
+    hmap(x, y) = 100 * x * (isthmus_width - x) + (myrand(400) - 200);
+  }
+
+  remaining_count -= (map.ysize - 2*polar_height) * 1;
+
+  /* add additional isthmus area randomly */
+  while(remaining_count > 0) {
+    for (y = polar_height; y < map.ysize/2; y++) {
+      for (x = 0; x < isthmus_width; x++) {
+	int new_terrain = random_new_land(x, y);
+	if(new_terrain == T_GRASSLAND){
+	  remaining_count--;
+	  map_set_terrain(x, y, T_GRASSLAND);
+	  map_set_continent(x, y, 1);
+	  hmap(x, y) = 100 * x * (isthmus_width - x) + (myrand(400) - 200);
+	}
+	if(remaining_count <= 0) {
+	  goto done_with_isthmus;
+	}
+      }
+    }
+    
+    for (y = map.ysize - polar_height - 1; y >= map.ysize/2; y--) {
+      for (x = 0; x < isthmus_width; x++) {
+	int new_terrain = random_new_land(x, y);
+	if(new_terrain == T_GRASSLAND){
+	  remaining_count--;
+	  map_set_terrain(x, y, T_GRASSLAND);
+	  map_set_continent(x, y, 1);
+	  hmap(x, y) = 100 * x * (isthmus_width - x) + (myrand(400) - 200);
+	}
+	if(remaining_count <= 0) {
+	  goto done_with_isthmus;
+	}
+      }
+    }
+  }
+ done_with_isthmus:
+  
+  /* setup peninsulas */
+  for(i = 0; i < game.nplayers; i++) {
+    /* direction is the direction to increment from the x and y location */
+    int direction = (i < peninsulas_on_one_side) ? -1 : 1;
+    int index = (direction == -1) ? i : i - peninsulas_on_one_side;
+    int width = (continent_percent < 95) 
+      ? peninsula_width
+	: peninsula_width + peninsula_separation - 1;/*Give more room */
+    int height = peninsula_height-polar_height;
+    int peninsula_remaining_count = 
+      MIN(width*height,
+	  ((width+peninsula_separation)*height*continent_percent)/100);
+    x = index * (peninsula_width + peninsula_separation) 
+      + isthmus_width + peninsula_separation;
+    y = (direction == -1) 
+      ? peninsula_height 
+	: map.ysize - 1 - peninsula_height;
+    create_peninsula(x,y,i,width,height,direction,peninsula_remaining_count);
+  }
+
+  map.num_start_positions = game.nplayers;
+  
+  /* setup terrain */
+  make_mountains(1600);
+  make_swamps();
+  make_forests();
+  make_deserts();
+  make_plains();
+  make_fair();
+  make_rivers();
+
+  /* create isthmus road */
+  {
+    int last_x, middle_x = isthmus_width/2;
+    last_x = middle_x;
+    for (y = polar_height - 1; y < map.ysize - polar_height + 1; y++) {
+      int best_x = middle_x;
+      int min_build = 100;
+      for(x = MAX(last_x - 1, middle_x - 1);
+	  x != MIN(last_x + 1,middle_x + 1) + 1; x++) {
+	if(land_terrain(x,y) && map_build_road_time(x,y) < min_build) {
+	  best_x = x;
+	  min_build = map_build_road_time(x,y);
+	}
+      }
+      map_set_special(best_x,y,S_ROAD);
+      last_x = best_x;
+    }
+  }
+  
+
+  free(height_map);
+	
+}
diff -urw freeciv-1.14.0/server/mapgen.h freeciv/server/mapgen.h
--- freeciv-1.14.0/server/mapgen.h	2002-02-05 14:05:51.000000000 -0500
+++ freeciv/server/mapgen.h	2003-03-28 12:19:44.000000000 -0500
@@ -15,7 +15,7 @@
 
 void assign_continent_numbers(void);
 void map_fractal_generate(void);
-void create_start_positions(void);
+int create_start_positions(void);
 void adjust_terrain_param(void);
 
 #endif  /* FC__MAPGEN_H */
diff -urw freeciv-1.14.0/server/savegame.c freeciv/server/savegame.c
--- freeciv-1.14.0/server/savegame.c	2002-12-08 18:32:30.000000000 -0500
+++ freeciv/server/savegame.c	2003-04-02 18:45:39.000000000 -0500
@@ -1862,6 +1862,15 @@
 	secfile_lookup_int_default(file, game.allowed_city_names,
 				   "game.allowed_city_names"); 
 
+    game.slowai_tech = secfile_lookup_int_default(file,
+	GAME_DEFAULT_SLOWAI_TECH, "game.slowai_tech");
+    game.slowai_grow = secfile_lookup_int_default(file,
+	GAME_DEFAULT_SLOWAI_GROW, "game.slowai_grow");
+    game.check_isles = secfile_lookup_int_default(file,
+	GAME_DEFAULT_CHECK_ISLES, "game.check_isles");
+    game.best_isles = secfile_lookup_bool_default(file,
+	GAME_DEFAULT_BEST_ISLES, "game.best_isles");
+
     if(game.civstyle == 1) {
       string = "civ1";
     } else {
@@ -1989,17 +1998,15 @@
       && secfile_lookup_bool_default(file, TRUE, "game.save_random")
       && game.load_options.load_random) {
     RANDOM_STATE rstate;
-    rstate.j = secfile_lookup_int(file,"random.index_J");
-    rstate.k = secfile_lookup_int(file,"random.index_K");
-    rstate.x = secfile_lookup_int(file,"random.index_X");
-    for(i=0;i<8;i++) {
-      char name[20];
-      my_snprintf(name, sizeof(name), "random.table%d",i);
-      string=secfile_lookup_str(file,name);
-      sscanf(string,"%8x %8x %8x %8x %8x %8x %8x", &rstate.v[7*i],
-	     &rstate.v[7*i+1], &rstate.v[7*i+2], &rstate.v[7*i+3],
-	     &rstate.v[7*i+4], &rstate.v[7*i+5], &rstate.v[7*i+6]);
-    }
+    rstate.dice_counter = secfile_lookup_int(file,"random.index_dice_counter");
+    rstate.r_place = secfile_lookup_int(file,"random.r_place");
+    string=secfile_lookup_str(file,"random.table");
+    sscanf(string,
+      "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+      &rstate.v[0], &rstate.v[1], &rstate.v[2], &rstate.v[3],
+      &rstate.v[4], &rstate.v[5], &rstate.v[6], &rstate.v[7],
+      &rstate.v[8], &rstate.v[9], &rstate.v[10], &rstate.v[11],
+      &rstate.v[12], &rstate.v[13], &rstate.v[14], &rstate.v[15]);
     rstate.is_init = TRUE;
     set_myrand_state(rstate);
   } else {
@@ -2185,6 +2192,11 @@
   secfile_insert_int(file, game.watchtower_extra_vision, "game.watchtower_extra_vision");
   secfile_insert_int(file, game.allowed_city_names, "game.allowed_city_names");
 
+  secfile_insert_int(file, game.slowai_tech, "game.slowai_tech");
+  secfile_insert_int(file, game.slowai_grow, "game.slowai_grow");
+  secfile_insert_int(file, game.check_isles, "game.check_isles");
+  secfile_insert_bool(file, game.best_isles, "game.best_isles");
+
   if (TRUE) {
     /* Now always save these, so the server options reflect the
      * actual values used at the start of the game.
@@ -2212,23 +2224,19 @@
   secfile_insert_int(file, game.randseed, "game.randseed");
   
   if (myrand_is_init() && game.save_options.save_random) {
+    char vec[33];
     RANDOM_STATE rstate = get_myrand_state();
     secfile_insert_int(file, 1, "game.save_random");
     assert(rstate.is_init);
 
-    secfile_insert_int(file, rstate.j, "random.index_J");
-    secfile_insert_int(file, rstate.k, "random.index_K");
-    secfile_insert_int(file, rstate.x, "random.index_X");
-
-    for(i=0;i<8;i++) {
-      char name[20], vec[100];
-      my_snprintf(name, sizeof(name), "random.table%d", i);
-      my_snprintf(vec, sizeof(vec),
-		  "%8x %8x %8x %8x %8x %8x %8x", rstate.v[7*i],
-		  rstate.v[7*i+1], rstate.v[7*i+2], rstate.v[7*i+3],
-		  rstate.v[7*i+4], rstate.v[7*i+5], rstate.v[7*i+6]);
-      secfile_insert_str(file, vec, name);
+    secfile_insert_int(file, rstate.dice_counter, "random.index_dice_counter");
+    secfile_insert_int(file, rstate.r_place, "random.r_place");
+
+    vec[0]='\0';
+    for(i=0;i<16;i++) {
+      my_snprintf(vec, sizeof(vec),"%s%02x",vec,rstate.v[i]);
     }
+      secfile_insert_str(file, vec, "random.table");
   } else {
     secfile_insert_int(file, 0, "game.save_random");
   }
diff -urw freeciv-1.14.0/server/settlers.c freeciv/server/settlers.c
--- freeciv-1.14.0/server/settlers.c	2002-11-15 22:14:22.000000000 -0500
+++ freeciv/server/settlers.c	2003-04-02 18:46:46.000000000 -0500
@@ -34,6 +34,7 @@
 #include "aiunit.h"
 #include "aidata.h"
 
+#include "rand.h"
 #include "settlers.h"
 
 /* negative: in_city_radius, 0: unassigned, positive: city_des */
@@ -1262,8 +1263,8 @@
   /* Decide whether to build a new city:
    * if so, modify: gx, gy, best_newv, best_act
    */
-  if (unit_flag(punit, F_CITIES) &&
-      pplayer->ai.control) {
+  if (unit_flag(punit, F_CITIES) && pplayer->ai.control &&
+      (myrand(101) <= game.slowai_grow)) {
     int nx, ny;
     int want = evaluate_city_building(punit, &nx, &ny, &ferryboat);
 
diff -urw freeciv-1.14.0/server/srv_main.c freeciv/server/srv_main.c
--- freeciv-1.14.0/server/srv_main.c	2002-10-11 19:35:50.000000000 -0400
+++ freeciv/server/srv_main.c	2003-04-02 18:50:50.000000000 -0500
@@ -1798,6 +1798,7 @@
 void srv_main(void)
 {
   int i;
+  int is_good_map = 1;
 
   /* make sure it's initialized */
   if (!has_been_srv_init) {
@@ -1944,6 +1945,13 @@
   if(game.is_new_game)
     generate_ai_players();
    
+  if (game.check_isles == 1)
+      game.check_isles = game.nplayers;
+ 
+  /* This is a loop which will recreate the map in case the map
+     generator decides the generated map is not good enough */
+  do {
+
   /* if we have a tile map, and map.generator==0, call map_fractal_generate
      anyway, to make the specials and huts */
   if(map_is_empty() || (map.generator == 0 && game.is_new_game))
@@ -1975,10 +1983,23 @@
     /* we don't want random start positions in a scenario which already
        provides them.  -- Gudy */
     if(map.num_start_positions==0) {
-      create_start_positions();
+      is_good_map = create_start_positions();
     }
   }
 
+  /* we aren't verifying, ensure a positive return. */
+  if (!game.check_isles)
+      is_good_map = 1;
+
+  /* Save the whales, free the mallocs */
+  if(is_good_map == 0) {
+      players_iterate(pplayer) {
+          free(pplayer->private_map);
+          } players_iterate_end;
+  }
+
+  } while(is_good_map == 0);
+
   initialize_move_costs(); /* this may be the wrong place to do this */
   generate_minimap(); /* for city_desire; saves a lot of calculations */
 
diff -urw freeciv-1.14.0/server/stdinhand.c freeciv/server/stdinhand.c
--- freeciv-1.14.0/server/stdinhand.c	2002-11-15 22:14:22.000000000 -0500
+++ freeciv/server/stdinhand.c	2003-04-02 18:54:43.000000000 -0500
@@ -239,7 +239,13 @@
        "additional\n"
        "    smaller islands.\n"
        "5 = one or more large earthlike continents with some scatter.\n"
-       "Note: values 2,3 and 4 generate \"fairer\" (but more boring) "
+       "6 = equally sized peninsulas with one player each surrounding\n"
+       "    an inland sea.\n"
+       "7 = generates maps based on simulated tectonic plates algorithims\n"
+       "    which produces more realistic looking maps.\n"
+       "8 = same as 7, but breaks the islands apart better to work with\n"
+       "    the seperate islands setting.\n"
+       "Note: values 2,3,4 and 6 generate \"fairer\" (but more boring) "
        "maps.\n"
        "(Zero indicates a scenario map.)"), NULL,
 	  MAP_MIN_GENERATOR, MAP_MAX_GENERATOR, MAP_DEFAULT_GENERATOR)
@@ -820,6 +826,37 @@
 	     "40=debuging logging."), NULL, 
 	  0, 40, 20)
 
+   GEN_INT("slowaitech", game.slowai_tech, SSET_RULES_FLEXIBLE, SSET_SERVER_ONLY,
+       N_("Adjust AI tech advancement"),
+       N_("This value determines how much slower the AI will learn"
+	   "new technologies compared to human players. Setting a value "
+	   "greater then 1 will slow their advancement that many times."), NULL,
+       GAME_MIN_SLOWAI_TECH, GAME_MAX_SLOWAI_TECH, GAME_DEFAULT_SLOWAI_TECH)
+
+   GEN_INT("slowaigrowth", game.slowai_grow, SSET_RULES_FLEXIBLE, SSET_SERVER_ONLY,
+       N_("Adjust city growth by %"), 
+       N_("This value determines how much slower the AI will expand in"
+	   "relation to human players. Setting a percent value under "
+	   "100 will cause them to expand at about the specified rate "
+	   "as compared to normal AI expansion."), NULL,
+       GAME_MIN_SLOWAI_GROW, GAME_MAX_SLOWAI_GROW, GAME_DEFAULT_SLOWAI_GROW)
+
+   GEN_INT("checkisles", game.check_isles, SSET_MAP_GEN, SSET_SERVER_ONLY,
+       N_("Try to create a number of islands to start."),
+       N_("Setting this causes the map generator to discard maps that "
+	   "create less than this number of valid islands.  A value of 1 "
+	   "means that all players get their own island."), NULL,
+       GAME_MIN_CHECK_ISLES, GAME_MAX_CHECK_ISLES, GAME_DEFAULT_CHECK_ISLES)
+
+   GEN_BOOL("bestisles", game.best_isles, SSET_MAP_GEN, SSET_SERVER_ONLY,
+       N_("Players get best islands"),
+       N_("This enables algorithims that shuffle the starting positions "
+	   "such that human players will get the best islands and AI the "
+	   "worse ones. This is mostly useful when used with the "
+	   "\"checkisles\" option, otherwise humans will be lumped "
+	   "together on the better isles and AI grouped on the worse "
+	   "ones."), NULL, GAME_DEFAULT_CHECK_ISLES)
+
   GEN_END
 };
 
