#-----------------------------------------------------------------------------
#	Copyright (c) 2005-2008 Laurent Di Cesare
#	Copyright (c) 2008 Firaxis Games, Inc. All rights reserved.
#-----------------------------------------------------------------------------
#
# FILE: Tectonics.py
# AUTHOR: Laurent Di Cesare (LDiCesare)
# PURPOSE: Provide a map with mountain ranges, preferably near the coasts.
# DESCRIPTION:
# Provide a map with several continents, possibly some big islands,
# and simulates some very rough plate tectonics to generate mountain ranges.
# The map is tuned to generate about 40% land and 60% water but only the
# number of plates is fixed, not the actual size of the plates, so landmasses
# sizes may vary quite a bit.
# It is an adaptation to CivIV of an algorithm originally developped for
# the Clash of Civilizations (http://clash.apolyton.net)
# VERSION 1.0 Initial version
# VERSION 1.1 Changed the moveplates and blur routines to avoid having
#                           big lumps of peaks propagating everywhere.
#             Added subduction
#             Hinted continents seeds to avoid the poles
# VERSION 2.0 Added climate management.
# VERSION 2.1 Made desert edges rougher.
#             Added first try at rivers.
#             Increased subduction
# VERSION 3.0 Added various landmasses (Pangaeas, Lakes, Islands).
#             Modified rivers
# VERSION 3.1 Lost when reinstalling windows and not backing it up.
#             It was great, though.
# VERSION 3.2 Provided new option for Earthlike, and grouped land masses
#             so 2/3rds are on the same hemisphere. Less ice.
# VERSION 3.3 Systematic use of climate map because I had bugged it away for
#             the main map type instead of pangaea. Tried to prevent players
#             from starting in the ice. Added hotspots.
# VERSION 3.4 Minor rewritings.
#             Added fault lines: Some hills and lakes will pop up inside
#             vast flat areas, forming a ridge line, but with lots of flat
#             lands inside. Not always noticeable but has a definite effect.
#             Corrected climate generation which didn't blow enough moisture.
# VERSION 3.5 Added several climate options. Tuned the starting locations.
# VERSION 3.6 Roughed the edges of the various climate zones to avoid excess
#             of straight limits.
#             Added Mediterranean land type (inner sea).
#             Added No Ice option that replaces ice with tundra and tundra
#             with grass, otherwise behaves as normal humidity level.
# VERSION 3.7 Mediterranean map rewrite: East is always land, more and bigger
#             islands, correct latitude used for feature generation.
# VERSION 3.8 Fixed WrapY error.
# VERSION 3.9 Fixed subduction error.
# VERSION 3.10 Shapes of plates are somewhat less square, and rivers in desert
#             are always floodplains even after the default algorithm adds
#             them near players' starting location
# VERSION 3.11 Climate generation rewritten, rivers less likely to start
#             in desert and more often from hills.
# VERSION 3.12 Broke east-west climate lines, smoothed desert-grass
#             transitions always through plains.
# VERSION 3.13 More mountains (second pass of movePlates). Terra option.
# VERSION 3.14 Fixed starting plot generation errors.
# VERSION 3.15 Added an option not to group civs on Terra option,
#							 Tuned Terra landmasses (mostly Africa, Greenland), removed
#							 Antarctic landmass (too many barbs spawning there).
# VERSION 3.16 Included Firaxis code for translating the options.
#							Kept my copyrights.
#             Added more rivers. (Also aborted try at heghtmap for rivers.)
#						  Updated the Terra option to have much better looking Arabia.
# TODO The shape of the plates should be less polygonal and more random
#      (more round than rectangular)
#      The number of plates could be more tunable.
#      I could also rewrite the whole rivers thing...

# Modified by Terkhen
# VERSION 3.19_mst - 21.Sep.2016
#  - Fixed [Planetfall], do not use snow and desert terrain, use their Planetfall equivalents instead.
#
# Modified by Terkhen
# VERSION 3.18_mst - 17.Aug.2016
#  - Fixed, use terrain, feature and improvement definitions from MST.
#
# Modified by Terkhen
# VERSION 3.17_mst - 08.Dic.2014
#  - Added, save/load map options.
#  - Added, compatibility with RandomMap.
#  - Changed, resource balance option.
#  - Changed, use TXT strings instead of hardcoded ones.
#
# Modified by Temudjin
# VERSION 3.16a_mst - 15.Mar.2011
#  - Fixed, the land/water percentages are somewhat more realistic now
#  - Fixed [Planetfall], tried to lumpify normal terrain in 'Planetfall'
#  - Fixed [Planetfall], now compatibile with Planetfalls' 'Scattered Pods' mod option
#  - Fixed [Mars Now!], team start normalization
#  - Added, new map option for expanded coastal waters (like Civ5)
#  - Added [Planetfall], option to use original Planetfall Highlands Generator
#  - Added [Mars Now!], new map option: 'Sands of Mars'/'Terraformed Mars'
#  - Changed, fewer rivers from lakes
#  - Changed, smaller maximum number of BigDent/BigBogs for Island/Terra options
#  - Changed, removed Whale boni for Lakes (30% Water) option
#  - Changed, stratified custom map option process
#  - Changed, stratified normalization process
#  - Changed, reorganised function call sequence within map building process
#  - Changed [Mars Now!], using dedicated terrain generator
#
# VERSION 3.16_mst - 15.Jul.2010
#  - use MapScriptTools
#  - compatibility with 'Planetfall'
#  - compatibility with 'Mars Now!'
#  - supports any number of players
#  - add Map Option: TeamStart
#  - add Marsh terrain, if supported by mod
#  - add Deep Ocean terrain, if supported by mod
#  - add rivers on islands
#  - allow more world sizes, if supported by mod
#  - add Map Features ( Kelp, HauntedLands, CrystalPlains )
#  - add Map Regions ( BigDent, BigBog, ElementalQuarter, LostIsle )
#  - better balanced resources
#  - check for Temudjin's Cool Starting Plots
#  - print stats of mod and map
#

from CvPythonExtensions import *
import CvUtil
import CvMapGeneratorUtil


gc = CyGlobalContext()
map = CyMap()
dice = gc.getGame().getMapRand()

##################################################################################
## MapScriptTools Interface by Temudjin                                      START
##################################################################################
import MapScriptTools as mst
balancer = mst.bonusBalancer

# The following two functions are not exactly neccessary, but they should be
# in all map-scripts. Just comment them out if they are already in the script.
# ----------------------------------------------------------------------------
def getVersion():
	return "3.19_mst"

def getDescription():
	return "TXT_KEY_MAP_SCRIPT_TECTONICS_DESCR"

# #################################################################################################
# ######## randomMapBeforeInit() - Starts the map-generation process, called by RandomMap to set
# ######## the map options
# #################################################################################################
def randomMapBeforeInit(moWorldShape, moResources, moCoastalWaters, moTeamStart, moMarsTheme):
	print "-- randomMapBeforeInit()"

	# Avoid errors while printing custom options.
	global op
	op = {}

	# Map options of this script
	global mapOptionLandmass, mapOptionAridity, mapOptionCoastalWaters, mapOptionResources
	global mapOptionLandscape, mapOptionTeamStart, mapOptionMarsTheme

	# Options chosen in Random Map
	mapOptionResources = moResources
	mapOptionCoastalWaters = moCoastalWaters
	mapOptionTeamStart = moTeamStart
	mapOptionMarsTheme = moMarsTheme

	# All other options are chosen randomly.
	mapOptionLandmass = CyGlobalContext().getGame().getMapRand().get(8, "Tectonics.randomMapBeforeInit(), mapOptionLandmass")
	mapOptionAridity = CyGlobalContext().getGame().getMapRand().get(4, "Tectonics.randomMapBeforeInit(), mapOptionAridity")
	mapOptionLandscape = mst.iif(mst.bPfall, CyGlobalContext().getGame().getMapRand().get(3, "Tectonics.randomMapBeforeInit(), mapOptionLandscape"), None)

# #################################################################################################
# ######## beforeInit() - Starts the map-generation process, called after the map-options are known
# ######## - map dimensions, latitudes and wrapping status are not known yet
# ######## - handle map specific options
# #################################################################################################
def beforeInit():
	print "-- beforeInit()"

	# Selected map options
	global mapOptionLandmass, mapOptionAridity, mapOptionCoastalWaters, mapOptionResources
	global mapOptionLandscape, mapOptionTeamStart, mapOptionMarsTheme
	mapOptionResources = map.getCustomMapOption(0)
	mapOptionLandmass = map.getCustomMapOption(1)
	mapOptionAridity = map.getCustomMapOption(2)
	mapOptionCoastalWaters = mst.iif(mst.bPfall, None, map.getCustomMapOption(3))
	mapOptionLandscape = mst.iif(mst.bPfall, map.getCustomMapOption(3), None)
	mapOptionTeamStart = mst.iif(mst.bMars, None, map.getCustomMapOption(4))
	mapOptionMarsTheme = mst.iif(mst.bMars, map.getCustomMapOption(4), None)

# #######################################################################################
# ######## beforeGeneration() - Called from system after user input is finished
# ######## - define your latitude formula, get the map-version
# ######## - create map options info string
# ######## - initialize the MapScriptTools
# ######## - initialize MapScriptTools.BonusBalancer
# #######################################################################################
def beforeGeneration():
	print "-- beforeGeneration()"

	# Create evaluation string for latitudes
	compGetLat = None
	if mapOptionLandmass == 5:
		compLat = "90 * ( 5/18.0 + 4*(%i-y) / (%i*9.0) )" % (map.getGridHeight(),map.getGridHeight())
	# Create mapInfo string
	mapInfo = ""

	# Backup current language
	iLanguage = CyGame().getCurrentLanguage()
	# Force english language for logs
	CyGame().setCurrentLanguage(0)

	for opt in range( getNumCustomMapOptions() ):
		nam = getCustomMapOptionName( [opt] )
		sel = map.getCustomMapOption( opt )
		txt = getCustomMapOptionDescAt( [opt,sel] )
		mapInfo += "%27s:   %s\n" % ( nam, txt )

	# Restore current language
	CyGame().setCurrentLanguage(iLanguage)

	# Obtain the map options in use.
	lMapOptions = []
	for opt in range( getNumCustomMapOptions() ):
		iValue = 0 + map.getCustomMapOption( opt )
		lMapOptions.append( iValue )

	# Save used map options.
	mst.mapOptionsStorage.writeConfig(lMapOptions)

	# Initialize MapScriptTools
	mst.getModInfo( getVersion(), None, mapInfo )

	# Initialize MapScriptTools
	mst.getModInfo( getVersion(), compGetLat, mapInfo )

	# Determine global Mars Theme
	mst.bSandsOfMars = (mapOptionMarsTheme == 0)

	# Initialize MapScriptTools.BonusBalancer
	balancer.initialize( mapOptionResources == 1 ) # balance boni if desired, place missing boni, move minerals

# #######################################################################################
# ######## generateTerrainTypes() - Called from system after generatePlotTypes()
# ######## - SECOND STAGE in 'Generate Map'
# ######## - creates an array of terrains (desert,plains,grass,...) in the map dimensions
# #######################################################################################
def generateTerrainTypes():
	print "-- generateTerrainTypes()"

	# Planetfall: more highlands
	mst.planetFallMap.buildPfallHighlands()
	# Prettify the map - change coastal peaks to hills with 50% chance; default: 66%
	mst.mapPrettifier.hillifyCoast( 50 )
	# Prettify map: Connect small islands
	# mst.mapPrettifier.bulkifyIslands()

	# If your active mod is 'Planetfall'/'Mars Now!', you will have to use a different terrainGenerator.
	if mst.bPfall:
		terraingen = mst.MST_TerrainGenerator()
	elif mst.bMars:
		iDesert = mst.iif( mst.bSandsOfMars, 16, 32 )
		terraingen = mst.MST_TerrainGenerator_Mars( iDesert )
	else:
		# Normally use original Tectonics terrain-generator.
		terraingen = ClimateGenerator()

	# Create the terrain and return the result.
	terrainTypes = terraingen.generateTerrain()
	print "-- testtt"
	return terrainTypes

# #######################################################################################
# ######## addRivers() - Called from system after generateTerrainTypes()
# ######## - THIRD STAGE in 'Generate Map'
# ######## - puts rivers on the map
# #######################################################################################
def addRivers():
	print "-- addRivers()"

	# Generate Marsh-terrain within latitude zones (default: 5, 10, (0,18), (45,63) ).
	# The frequency of transformation as well as the zones may be changed by first
	# calling mst.marshMaker.initialize() with the appropriate parameters.
	mst.marshMaker.initialize( 4, 20, (0,25), (50,75) )
	mst.marshMaker.convertTerrain()
	# Solidify marsh between 3 [Arid] and 7 [Tropical] percent.
	if not mst.bPfall:
		if mst.bMarsh:
			iAridity =  mst.iif( mapOptionAridity==0, 2, 0 )		# Arid
			iAridity += mst.iif( mapOptionAridity==2, -2, 0 )		# Wet
			marshPer = 5 - iAridity
			mst.mapPrettifier.percentifyTerrain( (mst.etMarsh,marshPer), (mst.etTundra,1), (mst.etGrass,2) )

	# Expand coastal waters
	if mapOptionCoastalWaters == 1:
		mst.mapPrettifier.expandifyCoast()

	nMaxRegions = 3
	if mapOptionLandmass in [4,6,7]: 			# Islands, Terra, TerraRandom
		nMaxRegions = 1

	# Build between 0..2 mountain-ranges.
	mst.mapRegions.buildBigDents()
	# Build between 0..2 bog-regions.
	mst.mapRegions.buildBigBogs()

	# Generate DeepOcean-terrain if mod allows for it
	mst.deepOcean.buildDeepOcean()

	# Prettify the map - create better connected deserts and plains
	if not mst.bPfall:
		mst.mapPrettifier.lumpifyTerrain( mst.etDesert, mst.etPlains, mst.etGrass )
		if not mst.bMars:
			mst.mapPrettifier.lumpifyTerrain( mst.etPlains, mst.etDesert, mst.etGrass )

	# No standard rivers on Mars
	if not mst.bMars:
		# Tectonics has own river-system
		riverGenerator = riversFromSea()
		riverGenerator.seedRivers()

	# Put rivers on small islands.
	mst.riverMaker.islandRivers()									# islands between 6 and 50 tiles

# #######################################################################################
# ######## addLakes() - Called from system after addRivers()
# ######## - FOURTH STAGE in 'Generate Map'
# ######## - puts lakes on the map
# #######################################################################################
def addLakes():
	print "-- addLakes()"
	if not mst.bMars:
		CyPythonMgr().allowDefaultImpl()

# #######################################################################################
# ######## addFeatures() - Called from system after addLakes()
# ######## - FIFTH STAGE in 'Generate Map'
# ######## - puts features on the map
# #######################################################################################
def addFeatures():
	print "-- addFeatures()"

	# Prettify the map - kill off spurious lakes; default: 75% chance
	mst.mapPrettifier.connectifyLakes( 90 )
	# Sprout rivers from lakes.
	mst.riverMaker.buildRiversFromLake( None, 33, 2, 2 )	# all lakes, 33% chance, 2 rivers, lakesize>=2

	# select feature generator
	if mst.bMars:
		featuregen = mst.MST_FeatureGenerator()
	else:
		if (5 == mapOptionLandmass):
			featuregen = MediterraneanFeatureGenerator()				# Mediterranean
		elif (3 == mapOptionAridity):
			featuregen = NoIceFeatureGenerator()						# Lakes
		else:
			featuregen = mst.MST_FeatureGenerator()
	# generate features
	featuregen.addFeatures()

	# Prettify the map - transform coastal volcanos; default: 66% chance
	mst.mapPrettifier.beautifyVolcanos()
	# Mars Now!: lumpify sandstorms
	if mst.bMars: mst.mapPrettifier.lumpifyFeature( mst.efSandStorm, FeatureTypes.NO_FEATURE )
	# Planetfall: handle shelves and trenches
	if mst.bPfall: mst.planetFallMap.buildPfallOcean()
	# FFH: build ElementalQuarter; default: 5% chance
	mst.mapRegions.buildElementalQuarter()


	# Print featureMap
	mst.mapPrint.buildFeatureMap( True, "normalizeAddExtras()" )

# ############################################################################################
# ######## normalizeStartingPlotLocations() - Called from system after starting-plot selection
# ######## - FIRST STAGE in 'Normalize Starting-Plots'
# ######## - change assignments to starting-plots
# ############################################################################################
def normalizeStartingPlotLocations():
	print "-- normalizeStartingPlotLocations()"

	# build Lost Isle
	# - this region needs to be placed after starting-plots are first assigned
	mst.mapRegions.buildLostIsle( chance=33, minDist=7, bAliens=mst.choose(33,True,False) )

	if mst.bMars:
		# Mars Now! uses no teams
		CyPythonMgr().allowDefaultImpl()
	else:
		if mapOptionTeamStart == 0:
			CyPythonMgr().allowDefaultImpl()					# by default civ places teams near to each other
			# mst.teamStart.placeTeamsTogether( True, True )	# use teamStart to place teams near to each other
		elif mapOptionTeamStart == 1:
			mst.teamStart.placeTeamsTogether( False, True )		# shuffle starting-plots to separate teams
		elif mapOptionTeamStart == 2:
			mst.teamStart.placeTeamsTogether( True, True )		# randomize starting-plots (may be near or not)
		else:
			mst.teamStart.placeTeamsTogether( False, False )	# leave starting-plots alone

# ############################################################################################
# ######## normalizeAddRiver() - Called from system after normalizeStartingPlotLocations()
# ######## - SECOND STAGE in 'Normalize Starting-Plots'
# ######## - add some rivers if needed
# ############################################################################################
def normalizeAddRiver():
	print "-- normalizeAddRiver()"
	if not mst.bMars:
		CyPythonMgr().allowDefaultImpl()

# ############################################################################################
# ######## normalizeRemovePeaks() - Called from system after normalizeAddRiver()
# ######## - THIRD STAGE in 'Normalize Starting-Plots'
# ######## - remove some peaks if needed
# ############################################################################################
# A hack. I remove the peaks and I use this as it is the first method called after normalizeAddRiver,
# which needs a post treatment, so it comes here.
def normalizeRemovePeaks():
	print "-- normalizeRemovePeaks()"
	# Force flood plains
	mapWidth = map.getGridWidth()
	mapHeight = map.getGridHeight()
	width = map.getGridWidth()
	height = map.getGridHeight()
	for x in range(width):
		for y in range(height):
			addFloodPlains(map.plot(x,y))
	# And now the peaks.
########## Temudjin Start
	if mst.bPfall: return
########## Temudjin End
	CyPythonMgr().allowDefaultImpl()

# ############################################################################################
# ######## normalizeAddLakesRiver() - Called from system after normalizeRemovePeaks()
# ######## - FOURTH STAGE in 'Normalize Starting-Plots'
# ######## - add some lakes if needed
# ############################################################################################
def normalizeAddLakes():
	print "-- normalizeAddLakes()"
	if not mst.bMars:
		CyPythonMgr().allowDefaultImpl()

# ############################################################################################
# ######## normalizeRemoveBadFeatures() - Called from system after normalizeAddLakes()
# ######## - FIFTH STAGE in 'Normalize Starting-Plots'
# ######## - remove bad features if needed
# ############################################################################################
def normalizeRemoveBadFeatures():
	print "-- normalizeRemoveBadFeatures()"
	return None

# ############################################################################################
# ######## normalizeRemoveBadTerrain() - Called from system after normalizeRemoveBadFeatures()
# ######## - SIXTH STAGE in 'Normalize Starting-Plots'
# ######## - change bad terrain if needed
# ############################################################################################
def normalizeRemoveBadTerrain():
	print "-- normalizeRemoveBadTerrain()"
	if not (mst.bPfall or mst.bMars):
		CyPythonMgr().allowDefaultImpl()

# ############################################################################################
# ######## normalizeAddFoodBonuses() - Called from system after normalizeRemoveBadTerrain()
# ######## - SEVENTH STAGE in 'Normalize Starting-Plots'
# ######## - add food if needed
# ############################################################################################
def normalizeAddFoodBonuses():
	print "-- normalizeAddFoodBonuses()"
	if mst.bMars:
		CyPythonMgr().allowDefaultImpl()

# ############################################################################################
# ######## normalizeAddGoodTerrain() - Called from system after normalizeAddFoodBonuses()
# ######## - EIGHTH STAGE in 'Normalize Starting-Plots'
# ######## - add good terrain if needed
# ############################################################################################
def normalizeAddGoodTerrain():
	print "-- normalizeAddGoodTerrain()"
	if not (mst.bPfall or mst.bMars):
		CyPythonMgr().allowDefaultImpl()

# This function will be called by the system, after the map was generated, after the
# starting-plots have been choosen, at the end of the normalizing process and
# before startHumansOnSameTile() which is the last map-function so called.
# - balance boni (depending on initialization also place missing boni and move minerals)
# - give names and boni to special regions
# - print plot-map and the difference-map to the call before
# - print other maps
# - print river-map with plots, rivers and starting-plots
# - print map and mod statistics
# --------------------------------------------------------------------------------------
def normalizeAddExtras():
	print "-- normalizeAddExtras()"

	# Balance boni, place missing boni and move minerals depending on initialization.
	if mapOptionLandmass == 3:							# lakes map option
		mst.bonusBalancer.normalizeAddExtras( '-BONUS_WHALE' )
	else:
		mst.bonusBalancer.normalizeAddExtras()

	# Do the default housekeeping
	CyPythonMgr().allowDefaultImpl()

	# Make sure marshes are on flatlands
	mst.marshMaker.normalizeMarshes()
	# Give extras to special regions
	mst.mapRegions.addRegionExtras()
	# Place special features on map
	mst.featurePlacer.placeFeatures()
	# Kill ice on warm edges
	mst.mapPrettifier.deIcifyEdges()

	# Print plotMap and differencePlotMap
	mst.mapPrint.buildPlotMap( True, "normalizeAddExtras()" )
	# Print areaMap
	mst.mapPrint.buildAreaMap( True, "normalizeAddExtras()" )
	# Print terrainMap
	mst.mapPrint.buildTerrainMap( True, "normalizeAddExtras()" )
	# Print featureMap
	mst.mapPrint.buildFeatureMap( True, "normalizeAddExtras()" )
	# Print bonusMap
	mst.mapPrint.buildBonusMap( True, "normalizeAddExtras()" )
	# Print manaMap if FFH
	if mst.bFFH: mst.mapPrint.buildBonusMap( True, "normalizeAddExtras():Mana", None, mst.mapPrint.manaDict )
	# Print riverMap
	mst.mapPrint.buildRiverMap( True, "normalizeAddExtras()" )
	# Print mod and map statistics
	mst.mapStats.mapStatistics()

# This function will be called at odd times by the system.
# 'Planetfall' wants nearer starting-plots
# If the script already has this function, return that result instead of zero or rename it.
def minStartingDistanceModifier():
	if mst.bPfall: return -25
	if mst.bMars: return -15
	return 0

################################################################
## Custom Map Option Interface by Temudjin                 START
################################################################
def setCustomOptions():
	""" Set all custom options in one place """
	global op	# { optionID: Name, OptionList, Default, RandomOpt }

	# Initialize options to the default values.
	lMapOptions = [0, 0, 1, 0, 0]

	# Try to read map options from the cfgFile.
	mst.mapOptionsStorage.initialize(lMapOptions, 'Tectonics')
	lMapOptions = mst.mapOptionsStorage.readConfig()

	optionLandmass = [ "TXT_KEY_MAP_SCRIPT_EARTH_70", "TXT_KEY_MAP_SCRIPT_EARTH_60",
	                   "TXT_KEY_MAP_SCRIPT_PANGAEA",  "TXT_KEY_MAP_SCRIPT_LAKES",
	                   "TXT_KEY_MAP_SCRIPT_ISLANDS",  "TXT_KEY_MAP_SCRIPT_MEDITERRANEAN",
	                   "TXT_KEY_MAP_SCRIPT_TERRA",    "TXT_KEY_MAP_SCRIPT_TERRA_OLD_WORLD_START" ]
	optionAridity =  [ "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_ARID", "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_NORMAL",
	                   "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_WET",  "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_NO_ICE" ]
	op = {
		   0: ["TXT_KEY_MAP_RESOURCES", ["TXT_KEY_MAP_RESOURCES_STANDARD", "TXT_KEY_MAP_RESOURCES_BALANCED"], lMapOptions[0], True],
	       1: ["TXT_KEY_MAP_SCRIPT_LANDMASS_TYPE", optionLandmass, lMapOptions[1], True],
	       2: ["TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY",       optionAridity, lMapOptions[2], True],
	       3: ["TXT_KEY_MAP_COASTS", ["TXT_KEY_MAP_COASTS_STANDARD", "TXT_KEY_MAP_COASTS_EXPANDED"], lMapOptions[3], True],
	       4: ["TXT_KEY_MAP_TEAM_START", ["TXT_KEY_MAP_TEAM_START_NEIGHBORS", "TXT_KEY_MAP_TEAM_START_SEPARATED", "TXT_KEY_MAP_TEAM_START_RANDOM"], lMapOptions[4], False],
	       "Hidden": mst.iif( mst.bPfall, 3, 2 )
	     }
	if mst.bMars:
		op[4] = ["TXT_KEY_MAP_MARS_THEME", ["TXT_KEY_MAP_MARS_THEME_SANDS_OF_MARS", "TXT_KEY_MAP_MARS_THEME_TERRAFORMED_MARS"], lMapOptions[4], False]
	elif mst.bPfall:
		op[3] = ["TXT_KEY_MAP_SCRIPT_TECTONICS_LANDSCAPE",    ["TXT_KEY_MAP_SCRIPT_TECTONICS_LANDSCAPE_PLANETFALL", "TXT_KEY_MAP_SCRIPT_TECTONICS_LANDSCAPE_DEFAULT"], lMapOptions[3], False]
	mst.printDict(op,"Tectonics Map Options:")

def isAdvancedMap():
	""" This map should show up in simple mode """
	return 0

# first function to be called by the map building process
def getNumHiddenCustomMapOptions():
	""" Default is used for the last n custom-options in 'Play Now' mode. """
	setCustomOptions()						# Define Options
	return op["Hidden"]

def getNumCustomMapOptions():
	""" Number of different user-defined options for this map """
	return len( op ) - 1

def getCustomMapOptionName(argsList):
	""" Returns name of specified option """
	optionID = argsList[0]
	translated_text = unicode(CyTranslator().getText(op[optionID][0], ()))
	return translated_text

def getNumCustomMapOptionValues(argsList):
	"""	Number of different choices for a particular setting """
	optionID = argsList[0]
	return len( op[optionID][1] )

def getCustomMapOptionDescAt(argsList):
	""" Returns name of value of option at specified row """
	optionID = argsList[0]
	valueID = argsList[1]
	translated_text = unicode(CyTranslator().getText(op[optionID][1][valueID], ()))
	return translated_text

def getCustomMapOptionDefault(argsList):
	"""	Returns default value of specified option """
	optionID = argsList[0]
	return op[optionID][2]

def isRandomCustomMapOption(argsList):
	"""	Returns a flag indicating whether a random option should be provided """
	optionID = argsList[0]
	return op[optionID][3]

################################################################
## Interfaces by Temudjin                                    END
################################################################

def isClimateMap():
	"""	Does not use the Climate options """
	return False
def isSeaLevelMap():
	"""	Does not use the Sea Level options """
	return False

def getTopLatitude():
	""" Default is 90. 75 is past the Arctic Circle """
	if (5 == mapOptionLandmass): return 65
	return 90
def getBottomLatitude():
	""" Default is -90. -75 is past the Antartic Circle """
	if (5 == mapOptionLandmass): return 25
	return -90

def getWrapX():
	if (5 == mapOptionLandmass): return False
	return True
def getWrapY():
	return False

##########


class voronoiMap:
	def __init__(self,landPlates,seaPlates,hotspotsF):
		self.dice = gc.getGame().getMapRand()
		self.mapWidth = map.getGridWidth()
		self.mapHeight = map.getGridHeight()
		self.plotTypes = [PlotTypes.PLOT_OCEAN] * (self.mapWidth*self.mapHeight)
		self.heightMap = [0] * (self.mapWidth*self.mapHeight)
		self.plateMap = [0] * (self.mapWidth*self.mapHeight)
		self.numContinents = landPlates
		self.hotSpotFrequency = hotspotsF
		self.numSeaPlates = seaPlates + 1 # plate 0 is for initialisation
		self.plate = [0] * (self.numContinents + self.numSeaPlates)
		# plateSize is a random number which gives the probability of growing a plate
		self.plateSize = [0] * (self.numContinents + self.numSeaPlates)
		self.altitudeVariation = 2
		self.peakAltitude = 12		########## Temudjin was 12
		self.hillAltitude = 9		########## Temudjin was 9
		self.landAltitude = 6		########## Temudjin was 6
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				i = y*self.mapWidth + x
				self.plotTypes[i] = PlotTypes.PLOT_OCEAN

	def generate(self):
		self.sowSeeds()
		self.fillPlates()
		self.movePlates(true)
		self.erode()
		self.movePlates(false)
		self.blur()
		self.addFaults()
		self.hotspots()
		self.createMap()
		self.finalizeMap()
		return self.plotTypes

	def sowSeeds(self):
		self.mostLands = self.dice.get(2,"mostland hemisphere")
		for i in range(self.numSeaPlates):
			self.plate[i] = self.dice.get(3,"Sea altitude")
		for i in range(self.numContinents):
			self.plate[self.numSeaPlates + i] = self.landAltitude + self.dice.get(3,"Land altitude")
		for i in range(self.numContinents + self.numSeaPlates):
			x, y = self.getCoord(i)
			while self.plateMap[y*self.mapWidth + x] != 0:
				x, y = self.getCoord(i)
			self.plateMap[y*self.mapWidth + x] = i
			self.plateSize[i] = 3 + self.dice.get(6,"Some randomness in plate sizes")	########## Temidjin was 2

	def getCoord(self,i):
		x = self.dice.get(self.mapWidth,"x seed for plate")
		if (i >= self.numSeaPlates + (self.numContinents/3)):
			y = 2 + self.dice.get(2*self.mapHeight/3,"y seed for plate")
			if (i >= self.numSeaPlates + 1 + (self.numContinents/3)):
				if (self.mostLands == 0):
					y = self.mapHeight - y - 1
			elif (self.mostLands == 1):
				y = self.mapHeight - y - 1
		else:
			y = self.dice.get(self.mapHeight,"y seed for plate")
		return x, y

	def fillPlates(self):
		filled = False
		bufferPlateMap = [0] * (self.mapWidth*self.mapHeight)
		while filled == False:
			filled = True
			for x in range(self.mapWidth):
				for y in range(self.mapHeight):
					i = y*self.mapWidth + x
					bufferPlateMap[i] = self.plateMap[i]
					if (self.plateMap[i] == 0):
						bufferPlateMap[i] = self.neighbour(x,y)
			for x in range(self.mapWidth):
				for y in range(self.mapHeight):
					i = y*self.mapWidth + x
					self.plateMap[i] = bufferPlateMap[i]
					if self.plateMap[i] == 0:
						filled = False
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				i = y*self.mapWidth + x
				self.heightMap[i] = self.plate[self.plateMap[i]] + self.dice.get(self.altitudeVariation,"Random variation of altitude")

	def movePlates(self,dontMoveSeaPlates):
		plates = self.numContinents + self.numSeaPlates
		xMoves = [0] * plates
		yMoves = [0] * plates
		subduction = [0] * plates
		min = 0
		if dontMoveSeaPlates:
			min = self.numSeaPlates
		for i in range(min,plates):
			xMoves[i] = self.dice.get(3,"moves") - 2
			yMoves[i] = self.dice.get(3,"moves") - 2
			subduction[i] = self.dice.get(10,"subduction")
		self.doMovePlates(xMoves,yMoves,subduction)

	def doMovePlates(self,xMoves,yMoves,subduction):
		mapSize = self.mapWidth*self.mapHeight
		#FIXME There must be a clone method somewhere?
		oldHeightMap = [0] * mapSize
		for i in range(mapSize):
			oldHeightMap[i] = self.heightMap[i]
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				currentCoord = y*self.mapWidth + x
				currentPlate = self.plateMap[currentCoord]
				if (xMoves[currentPlate] != 0 or yMoves[currentPlate] != 0):
					movedX = x + xMoves[currentPlate]
					movedY = y + yMoves[currentPlate]
					if (movedX >= 0 and movedX < self.mapWidth):
						if (movedY >= 0 and movedY < self.mapHeight):
							movedCoord = movedY*self.mapWidth + movedX
							targetPlate = self.plateMap[movedCoord]
							if (targetPlate != currentPlate):
								if (subduction[currentPlate] >= 6):
									sum = oldHeightMap[movedCoord] + oldHeightMap[currentCoord] + 2
									if (self.heightMap[movedCoord] < sum ):
										self.heightMap[movedCoord] = sum
									self.heightMap[currentCoord] = self.heightMap[currentCoord] -1
								else:
									sum = oldHeightMap[movedCoord] + oldHeightMap[currentCoord] -2
									if (self.heightMap[movedCoord] < sum and self.heightMap[movedCoord] >= self.landAltitude):
										self.heightMap[movedCoord] = sum
									if (self.heightMap[currentCoord] < sum and self.heightMap[currentCoord] >= self.landAltitude):
										self.heightMap[currentCoord] = sum

	def addFaults(self):
		"Adds faultlines to break up big flat land masses. Think Rift Valley."
		plates = self.numContinents + self.numSeaPlates
		width = [0] * plates
		height = [0] * plates
		sum = [0] * plates
		lastPlate = 0
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				currentCoord = y*self.mapWidth + x
				lastPlate = self.checkFault(currentCoord,sum,height,lastPlate)
		for y in range(self.mapHeight):
			for x in range(self.mapWidth):
				currentCoord = y*self.mapWidth + x
				lastPlate = self.checkFault(currentCoord,sum,width,lastPlate)
		for i in range(plates):
			if (width[i] != 0): self.verticalFault(i,width[i])
			elif (height[i] != 0): self.horizontalFault(i,height[i])

	def checkFault(self,currentCoord,sum,table,lastPlate):
		plates = self.numContinents + self.numSeaPlates
		faultLimit = 7
		if (self.heightMap[currentCoord] <= self.landAltitude):
			return 0
		if (self.heightMap[currentCoord] > self.hillAltitude):
			return 0
		currentPlate = self.plateMap[currentCoord]
		if (lastPlate != currentPlate):
			if (sum[lastPlate] >= 0):
				sum[lastPlate] = 0
			lastPlate = currentPlate
		elif (sum[lastPlate] >= 0):
			sum[lastPlate] = 1 + sum[lastPlate]
		if (sum[lastPlate] > faultLimit):
			table[lastPlate] = currentCoord
			sum[lastPlate] = -1
		return lastPlate

	def verticalFault(self,plateNumber,coord):
		nextCoord = coord - 3 + self.dice.get(6,"Fault position")
		mapSize = self.mapWidth*self.mapHeight
		while (nextCoord >= 0 and nextCoord < mapSize):
			if (self.plateMap[nextCoord] != plateNumber):
				break
			self.fault(nextCoord)
			nextCoord = nextCoord + self.mapWidth + self.dice.get(3,"Fault tilt") - 1

	def horizontalFault(self,plateNumber,coord):
		nextCoord = coord + (self.dice.get(6,"Fault position") - 3) * self.mapWidth
		mapSize = self.mapWidth*self.mapHeight
		max = coord + self.mapWidth
		if (max > mapSize):
			max = mapSize
		while (nextCoord >= 0 and nextCoord < max):
			if (self.plateMap[nextCoord] != plateNumber):
				break
			self.fault(nextCoord)
			nextCoord = nextCoord + 1 + (self.dice.get(3,"Fault tilt") - 1)*self.mapWidth

	def fault(self,coord):
		dieRoll = self.dice.get(20,"Fault line effect")
		if (dieRoll > 11):
			self.heightMap[coord] = self.hillAltitude + 1
		elif (dieRoll > 9):
			self.heightMap[coord] = 0

	def erode(self):
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				i = y*self.mapWidth + x
				if self.heightMap[i] > self.peakAltitude:
					self.heightMap[i] -= 2
				if self.heightMap[i] > self.hillAltitude:
					self.heightMap[i] -= 1
				hasSeaNeighbour = False
				hasHillNeighbour = False
				leftX = x-1
				if (leftX < 0):
					leftX = self.mapWidth - 1
				left = self.heightMap[leftX + y*self.mapWidth]
				if (left < self.landAltitude):
					hasSeaNeighbour = True
				elif (left > self.hillAltitude):
					hasHillNeighbour = True
				rightX = x+1
				if (rightX >= self.mapWidth):
					rightX = 0
				right = self.heightMap[rightX + y*self.mapWidth]
				if (right < self.landAltitude):
					hasSeaNeighbour = True
				elif (right > self.hillAltitude):
					hasHillNeighbour = True
				if (y>0):
					top = self.heightMap[x + (y-1)*self.mapWidth]
					if (top < self.landAltitude):
						hasSeaNeighbour = True
					elif (top > self.hillAltitude):
						hasHillNeighbour = True
				if (y<self.mapHeight - 2):
					bottom = self.heightMap[x + (y+1)*self.mapWidth]
					if (bottom < self.landAltitude):
						hasSeaNeighbour = True
					elif (bottom > self.hillAltitude):
						hasHillNeighbour = True
				if (hasSeaNeighbour):
					self.heightMap[i] = self.heightMap[i] - 1
				if (hasHillNeighbour):
					self.heightMap[i] = self.heightMap[i] - 1


	def min( height, left, right, top, bottom ):
		minHeight = height
		if ( minHeight > left ):
			minHeight = left
		if ( minHeight > right ):
			minHeight = right
		if ( minHeight > top ):
			minHeight = top
		if ( minHeight > bottom ):
			minHeight = bottom
		return minHeight

	def blur(self):
		#FIXME There must be a clone method somewhere?
		mapSize = self.mapWidth*self.mapHeight
		oldHeightMap = [0] * (mapSize)
		for i in range(mapSize):
			oldHeightMap[i] = self.heightMap[i]
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				i = y*self.mapWidth + x
				height = self.heightMap[i]
				leftX = x-1
				if (leftX < 0):
					leftX = self.mapWidth - 1
				left = oldHeightMap[leftX + y*self.mapWidth]
				rightX = x+1
				if (rightX >= self.mapWidth):
					rightX = 0
				right = oldHeightMap[rightX + y*self.mapWidth]
				top = height
				if (y>0):
					top = oldHeightMap[x + (y-1)*self.mapWidth]
				bottom = height
				if (y<self.mapHeight - 2):
					bottom = oldHeightMap[x + (y+1)*self.mapWidth]
				self.heightMap[i] = (height * 4 + left + right + top + bottom) / 8
				minHeight = min(height,left,right,top,bottom)
				if (minHeight >= self.peakAltitude):
					oldHeightMap[leftX + y*self.mapWidth] = self.hillAltitude + 1
					self.heightMap[leftX + y*self.mapWidth] = self.hillAltitude  + 1
					oldHeightMap[rightX + y*self.mapWidth] = self.hillAltitude  + 1
					self.heightMap[rightX + y*self.mapWidth] = self.hillAltitude  + 1
					if (y>0):
						oldHeightMap[x + (y-1)*self.mapWidth] = self.hillAltitude  + 1
						self.heightMap[x + (y-1)*self.mapWidth] = self.hillAltitude  + 1
					if (y<self.mapHeight - 2):
						oldHeightMap[x + (y+1)*self.mapWidth] = self.hillAltitude + 1
						self.heightMap[x + (y+1)*self.mapWidth] = self.hillAltitude + 1

	def hotspots(self):
		mapSize = self.mapWidth * self.mapHeight
		hotSpotsNumber = mapSize/self.hotSpotFrequency
		for hotspot in range(hotSpotsNumber):
			i = self.dice.get(mapSize,"Hotspot location")
			self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")

	def createMap(self):
		for y in range(self.mapHeight):
			for x in range(self.mapWidth):
				i = y*self.mapWidth + x
				height = self.heightMap[i]
				if (height > self.peakAltitude):
					if (self.dice.get(7,"Random pass") == 6):
						self.plotTypes[i] = PlotTypes.PLOT_HILLS
					else:
						self.plotTypes[i] = PlotTypes.PLOT_PEAK
				elif (height > self.hillAltitude):
					if (self.dice.get(20,"Random peak") == 19):
						self.plotTypes[i] = PlotTypes.PLOT_PEAK
					else:
						self.plotTypes[i] = PlotTypes.PLOT_HILLS
				elif (height > self.landAltitude):
					self.plotTypes[i] = PlotTypes.PLOT_LAND
				else:
					self.plotTypes[i] = PlotTypes.PLOT_OCEAN

	def finalizeMap(self):
		return

	def neighbour(self,x,y):
		roll = self.dice.get(10,"Some randomness in plate shapes")
		leftX = x-1
		if (leftX < 0):
			leftX = self.mapWidth - 1
		left = self.plateMap[leftX + y*self.mapWidth]
		if (left != 0):
			if (roll <= self.plateSize[left]):
				return left
		rightX = x+1
		if (rightX >= self.mapWidth):
			rightX = 0
		right = self.plateMap[rightX + y*self.mapWidth]
		if (right != 0):
			if (roll <= self.plateSize[right]):
				return right
		if (y>0):
			top = self.plateMap[x + (y-1)*self.mapWidth]
			if (top != 0):
				if (roll <= self.plateSize[top]):
					return top
		if (y<self.mapHeight - 2):
			bottom = self.plateMap[x + (y+1)*self.mapWidth]
			if (bottom != 0):
				if (roll <= self.plateSize[bottom]):
					return bottom
		return 0

class voronoiMediterraneanMap(voronoiMap):
	def __init__(self,numPlayers):
		voronoiMap.__init__(self,numPlayers*5/2, numPlayers,150)
		self.peakAltitude = 13

	def movePlates(self,dontMoveSeaPlates):
		if dontMoveSeaPlates:
			return
		voronoiMap.movePlates(self,true)

	def getCoord(self,i):
		mapWidthFraction = self.mapWidth/self.numSeaPlates
			# Sea plates
		if (i < self.numSeaPlates):
			x = mapWidthFraction*i + self.dice.get(mapWidthFraction,"x seed for sea plate")
			y = self.mapHeight/3 + self.dice.get(self.mapHeight/3,"y seed for plate")
		else:
			# One land plate to the east to link north and south
			if (i == self.numSeaPlates + self.numContinents - 1):
				x = self.dice.get(self.mapWidth - 2,"x seed for link land plate")
				y = self.mapHeight/3 + self.dice.get(self.mapHeight/3,"y seed for land plate")
			# Other land plates half north half south
			elif (i < self.numSeaPlates * 2):
				x = mapWidthFraction * (i - self.numSeaPlates) + self.dice.get(mapWidthFraction,"x seed for land plate")
				y = self.getLandY(0)
			elif (i >= self.numSeaPlates * 3):
				x = mapWidthFraction * (i - 2*self.numSeaPlates) + self.dice.get(mapWidthFraction,"x seed for land plate")
				y = self.getLandY(1)
			else:
				x = self.dice.get(self.mapWidth,"x seed for land plate")
				y = self.getLandY(i)
		return x, y

	def getLandY(self,i):
		y = 1 + self.dice.get(self.mapHeight/4,"y seed for land plate")
		if (i == 2*(i/2)):
			y = y + self.mapHeight*3/4 -1
		return y

	def hotspots(self):
		mapSize = self.mapWidth * self.mapHeight
		hotSpotsNumber = mapSize/self.hotSpotFrequency
		minX = 2
		maxX = self.mapWidth*9/10
		minY = self.mapHeight/10
		yRange = self.mapHeight*8/10
		for hotspot in range(hotSpotsNumber):
			x = minX + self.dice.get(maxX,"Hotspot X")
			y = minY + self.dice.get(yRange,"Hotspot Y")
			i = y*self.mapWidth + x
			while (self.plotTypes[i] != PlotTypes.PLOT_OCEAN):
				x = minX + self.dice.get(maxX,"Hotspot X")
				y = minY + self.dice.get(yRange,"Hotspot Y")
				i = y*self.mapWidth + x
			self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")
			self.spreadHotSpot(i)

	def spreadHotSpot(self,i):
		self.spreadIsland(i+1)
		self.spreadIsland(i-1)
		self.spreadIsland(i+self.mapWidth)
		self.spreadIsland(i-self.mapWidth)

	def spreadIsland(self,i):
		self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")
		if (self.heightMap[i] > self.landAltitude):
			self.spreadBigIsland(i+1)
			self.spreadBigIsland(i-1)
			self.spreadBigIsland(i+self.mapWidth)
			self.spreadBigIsland(i-self.mapWidth)

	def spreadBigIsland(self,i):
		if (self.heightMap[i] <= self.landAltitude):
			self.heightMap[i] = self.dice.get(self.peakAltitude,"Island altitude")

	def finalizeMap(self):
		# Make sure that the north and south borders are made of land.
		for y in range(self.mapHeight):
			for x in range(self.mapWidth):
				if self.checkY(y):
					i = y*self.mapWidth + x
					if (self.plotTypes[i] == PlotTypes.PLOT_OCEAN):
						self.plotTypes[i] = PlotTypes.PLOT_LAND
		# Make sure that there's a way north/south by foot or galley
		minEastWidth = self.mapWidth * 9 /10
		margin = self.mapWidth/10
		for y in range(self.mapHeight-1):
			for x in range(minEastWidth,self.mapWidth):
				if (x + 3 + self.dice.get(margin,"Border")) > self.mapWidth:
					i = y*self.mapWidth + x
					if (self.plotTypes[i] == PlotTypes.PLOT_OCEAN):
						self.plotTypes[i] = PlotTypes.PLOT_LAND

	def checkY(self,y):
		if (y > 9*self.mapHeight/10):
			y = self.mapHeight - y
		if (y < self.mapHeight/10):
			if (2 + self.dice.get(self.mapHeight/10,"Border")) > y:
				return True
		return False

class voronoiTerraMap(voronoiMap):
	def __init__(self):
		voronoiMap.__init__(self,12,8,800)
		self.altitudeVariation = 3

	def sowSeeds(self):
		for i in range(0,8):
			self.plate[i] = 2
		for i in range(8,20):
			self.plate[i] = self.landAltitude + 3
		#Pacific Ocean
		for i in range(self.mapHeight):
			self.plateMap[i*self.mapWidth] = 1
		for i in range(self.mapWidth/10):
			self.plateMap[self.mapHeight*self.mapWidth/2 -self.mapWidth/20 + i] = 1
		x = self.mapWidth/10
		y = self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 1
		self.plateSize[1] = 7
		#North Atlantic
		x = self.mapWidth/3
		ymin = 2*self.mapHeight/3
		ymax = 7*self.mapHeight/8
		for y in range(ymin,ymax):
			self.plateMap[x + y*self.mapWidth] = 2
		x = 3*self.mapWidth/10
		y = 3*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 2
		self.plateSize[2] = 7
		#South Atlantic
		x = self.mapWidth/3
		yMin = self.mapHeight/5
		yMax = self.mapHeight/3
		for y in range(yMin,yMax):
			self.plateMap[x + y*self.mapWidth] = 3
		for x in range(self.mapWidth/4,self.mapWidth/2):
			self.plateMap[self.mapWidth/3 + self.mapHeight/5*self.mapWidth] = 3
		x = self.mapWidth/3
		y= 5*self.mapHeight/12
		self.plateMap[x + y*self.mapWidth] = 3
		x = self.mapWidth/4 +1
		y = self.mapHeight/4
		self.plateMap[x + y*self.mapWidth] = 3
		self.plateSize[3] = 7
		#Arctic Ocean
		for i in range(self.mapWidth):
			self.plateMap[self.mapWidth*(self.mapHeight-2) + i] = 4
		self.plateSize[4] = 3
		#Mediterranean
		x = 4*self.mapWidth/9
		y = 3*self.mapHeight/4
		self.plateMap[x + y*self.mapWidth] = 5
		self.plateSize[5] = 4
		#Indian Ocean
		x = 3*self.mapWidth/4
		y = self.mapHeight/3
		self.plateMap[x + y*self.mapWidth] = 6
		x = 3*self.mapWidth/5
		y = self.mapHeight/3
		self.plateMap[x + y*self.mapWidth] = 6
		x = 2*self.mapWidth/3
		y = 9*self.mapHeight/20
		self.plateMap[x + y*self.mapWidth] = 6
		self.plateSize[6] = 7
		#Antarctic Ocean
		y = self.mapHeight/8
		for i in range(self.mapWidth):
			self.plateMap[i+y*self.mapWidth] = 7
		self.plateSize[7] = 4
		#North America
		x = self.mapWidth/5
		yMin = 4*self.mapHeight/5
		yMax = 6*self.mapHeight/7
		for y in range(yMin,yMax):
			self.plateMap[x + y*self.mapWidth] = 8
		self.plateMap[self.mapWidth/20 + yMax*self.mapWidth] = 8
		self.plateSize[8] = 8
		#South America
		x = self.mapWidth/5
		y = self.mapHeight/4
		self.plateMap[x + y*self.mapWidth] = 9
		y = self.mapHeight/3
		self.plateMap[x + y*self.mapWidth] = 9
		x = self.mapWidth/4 +1
		y = 2*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 9
		self.plateSize[9] = 5
		#Europe
		x = self.mapWidth/2
		y = 6*self.mapHeight/7
		self.plateMap[x + y*self.mapWidth] = 10
		x = 3*self.mapWidth/7
		y = 4*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 10
		self.plateSize[10] = 6
		#Asia
		x = 3*self.mapWidth/4
		y = 7*self.mapHeight/10
		self.plateMap[x + y*self.mapWidth] = 11
		x = 4*self.mapWidth/5
		y = 4*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 11
		x = 2*self.mapWidth/3
		y = 4*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 11
		self.plateSize[11] = 9
		#Africa
		x = 7*self.mapWidth/20
		y = 2*self.mapHeight/3 -1
		for i in range(self.mapWidth/12):
			self.plateMap[x  + i + y*self.mapWidth] = 12
		x = self.mapWidth/2
		y = 2*self.mapHeight/5
		self.plateMap[x + y*self.mapWidth] = 12
		self.plateSize[12] = 6
		#India
		x = 3*self.mapWidth/4
		y = 5*self.mapHeight/9
		self.plateMap[x + y*self.mapWidth] = 13
		self.plateSize[13] = 3
		#Oceania
		x = 4*self.mapWidth/5
		y = self.mapHeight/4 +1
		self.plateMap[x + y*self.mapWidth] = 14
		self.plateSize[14] = 4
		#Middle East
		x = 3*self.mapWidth/5
		y = 4*self.mapHeight/7
		self.plateMap[x + y*self.mapWidth] = 15
		self.plateSize[15] = 2
		self.plate[15] = self.landAltitude + 1
		#South East Asia
		x = 17*self.mapWidth/20
		y = 4*self.mapHeight/7
		self.plateMap[x + y*self.mapWidth] = 16
		self.plateSize[16] = 3
		self.plate[16] = self.landAltitude
		#Greenland
		x = 3*self.mapWidth/10
		y = 7*self.mapHeight/8
		self.plateMap[x + y*self.mapWidth] = 17
		self.plateSize[17] = 4
		#Scandinavia
		x = 3*self.mapWidth/7 -1
		y = 7*self.mapHeight/8
		self.plateMap[x + y*self.mapWidth] = 18
		self.plateSize[18] = 3
		self.plate[18] = self.landAltitude
		#Bering
		x = 9*self.mapWidth/10
		y = 5*self.mapHeight/6
		self.plateMap[x + y*self.mapWidth] = 19
		self.plateSize[19] = 5

	def finalizeMap(self):
		#Force Gibraltar straits
		x = 4*self.mapWidth/9
		y = 3*self.mapHeight/4
		for i in range(self.mapWidth/5):
			self.plotTypes[x + y*self.mapWidth - i] = PlotTypes.PLOT_OCEAN
		#Force cut between India and Oceania
		x = 7*self.mapWidth/10
		y = 4*self.mapHeight/9 -1
		for i in range(self.mapWidth/5):
			self.plotTypes[x + y*self.mapWidth + i] = PlotTypes.PLOT_OCEAN
		#Force Greenland to be an island
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if (self.plateMap[x + y*self.mapWidth] == 17):
					if (self.plateMap[x-1 + y*self.mapWidth] != 17):
						self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
						self.plotTypes[x + (y-1)*self.mapWidth] = PlotTypes.PLOT_OCEAN
		#Force Arabia
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if self.plateMap[x + y*self.mapWidth] == 15:
					if self.plateMap[x + (y-1)*self.mapWidth] != 15:
						self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
						self.plotTypes[x + (y-1)*self.mapWidth] = PlotTypes.PLOT_OCEAN
					if self.plateMap[x+1 + y*self.mapWidth] != 15:
						self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
						self.plotTypes[x+1 + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
		#Force Central America
		baseX = self.mapWidth/6
		x = baseX
		width = 2
		if (self.dice.get(10,"Width variation") > 8):
			width += 1
		if (width > 1 and self.dice.get(10,"Width variation") > 8):
			width -= 1
		for y in range(self.mapHeight/5,self.mapHeight*3/4):
			x = x + self.dice.get(3,"Not too straight") - 1
			if ( x - baseX > 4):
				x = baseX + 4
			if ( x - baseX < -4):
				x = baseX - 4
			if (self.plotTypes[x + y*self.mapWidth ] == PlotTypes.PLOT_OCEAN):
				for plot in range( width ):
					self.plotTypes[x + y*self.mapWidth + plot ] = PlotTypes.PLOT_LAND
					if (self.dice.get(10,"Some hills") > 5):
						self.plotTypes[x + y*self.mapWidth + plot ] = PlotTypes.PLOT_HILLS

	def movePlates(self,dontMoveSeaPlates):
		plates = self.numContinents + self.numSeaPlates
		if dontMoveSeaPlates:
			xMoves =     [0, 1, 0, 0, 0, 0, 0, 0,  -1,-1, 0,-1, 0, 0,-1, 0,-1, 1, 1, 0, 0]
			yMoves =     [0, 0, 0, 0,-1, 1, 1, 0,   0, 1,-1,-1, 0, 1, 0, 0, 0, 1, 0, 0, 0]
			subduction = [0, 9, 9, 0, 9, 0, 0, 0,   9, 9, 9, 0, 0, 9, 9, 9, 0, 9, 9, 0, 0]
		else:
			xMoves =     [0, 1, 0, 0, 0, 1,-1, 0,  -1,-1, 0, 1, 1,-1, 1, 0, 0,-1,-1, 1,-1]
			yMoves =     [0, 0, 0, 0, 1,-1, 0, 0,  -1, 1,-1,-1, 1,-1,-1,-1,-1,-1, 0, 1, 1]
			subduction = [0, 9, 9, 0, 9, 9, 9, 0,   9, 9, 9, 9, 0, 9, 9, 9, 0, 0, 9, 0, 0]
		self.doMovePlates(xMoves,yMoves,subduction)

class voronoiPangaeaMap(voronoiMap):
	def __init__(self,numPlayers):
		voronoiMap.__init__(self,numPlayers,1,1600)
		self.peakAltitude = 11
		self.hillAltitude = 7
		self.landAltitude = 3
		self.altitudeVariation = 3

	def sowSeeds(self):
		self.yTilt = self.dice.get(4,"YTilt")
		self.plate[0] = 0
		self.plate[1] = 0
		for x in range(self.mapWidth):
			self.plateMap[x] = 1
			self.plateMap[self.mapWidth + x] = 1
			self.plateMap[(self.mapHeight - 2)*self.mapWidth + x] = 1
			self.plateMap[(self.mapHeight - 1)*self.mapWidth + x] = 1
		for y in range(self.mapHeight):
			self.plateMap[y*self.mapWidth] = 1
			self.plateMap[y*self.mapWidth + 1] = 1
			self.plateMap[y*self.mapWidth + self.mapWidth - 2] = 1
			self.plateMap[y*self.mapWidth + self.mapWidth - 1] = 1
		for i in range(self.numContinents):
			self.plate[i + self.numSeaPlates] = 4 + self.dice.get(3,"Land altitude")
			x, y = self.getCoord(i)
			while self.plateMap[y*self.mapWidth + x] != 0:
				x, y = self.getCoord(i)
			self.plateMap[y*self.mapWidth + x] = i + 2

	def getCoord(self,i):
		step = self.mapWidth/(2*self.numContinents)
		x = self.mapWidth/4 + i*step + self.dice.get(step,"x seed for plate")
		quarterHeight = self.mapHeight/4
		eigthHeight = self.mapHeight/8
		y = quarterHeight + self.dice.get(self.mapHeight/2,"y seed for plate")
		if (self.yTilt == 0):
			y += i*(self.mapHeight/(self.numContinents*4)) - eigthHeight
		elif (self.yTilt == 1):
			y += eigthHeight - i*quarterHeight/self.numContinents
		elif (self.yTilt == 2):
			if (i%2 == 0):
				y += eigthHeight
			else:
				y -= eigthHeight
		# else: Let it be the way it was generated
		return x, y

class ClimateGenerator:
	def __init__(self):
		self.climate = mapOptionAridity
		self.map = gc.getMap()
		self.mapWidth = self.map.getGridWidth()
		if (self.climate == 0):                          # Arid
			self.maxWindForce = self.mapWidth / 12
		elif (self.climate == 1):                        # Normal
			self.maxWindForce = self.mapWidth / 8
		elif (self.climate == 2):                        # Wet
			self.maxWindForce = self.mapWidth / 6
		elif (self.climate == 3):                        # No ice
			self.maxWindForce = self.mapWidth / 8
		self.mapHeight = self.map.getGridHeight()
		self.terrainDesert = mst.etDesert
		self.terrainPlains = mst.etPlains
		self.terrainIce = mst.etSnow
		self.terrainTundra = mst.etTundra
		self.terrainGrass = mst.etGrass

		if (self.climate == 3):                        # No ice
			self.terrainIce = mst.etTundra
			self.terrainTundra = mst.etGrass
		self.terrain = [0] * (self.mapWidth*self.mapHeight)
		self.moisture = [0] * (self.mapWidth*self.mapHeight)
		self.dice = gc.getGame().getMapRand()

	def getLatitudeAtPlot(self, iX, iY):
		"returns a value in the range of 0-90 degrees"
		if (mapOptionLandmass == 5):         #  "Mediterranean"
			return 65 - (40 * (self.mapHeight - iY) / self.mapHeight)
		return self.map.plot(iX,iY).getLatitude()

	def generateTerrain(self):
		self.blowWinds()
		self.blur()
		self.computeTerrain()
		return self.terrain

	def computeTerrain(self):
		terrain = [0] * (self.mapWidth*self.mapHeight)
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if (self.map.plot(x,y).isWater()):
					self.terrain[y*self.mapWidth+x] = self.map.plot(x,y).getTerrainType()
				else:
					terrain[y*self.mapWidth+x] = self.getTerrain(self.getLatitudeAtPlot(x,y),self.moisture[y*self.mapWidth + x])
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if (not self.map.plot(x,y).isWater()):
					i = y*self.mapWidth+x
					self.terrain[i] = terrain[i]
					bias = self.dice.get(3,"Random terrain")
					if bias == 0 and y > 1:
						self.terrain[i] = terrain[i-self.mapWidth]
					if bias == 2 and y < self.mapHeight - 1:
						self.terrain[i] = terrain[i+self.mapWidth]
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if (not self.map.plot(x,y).isWater()):
					i = y*self.mapWidth+x
					if self.terrain[i] == self.terrainDesert:
						if y > 1 and y < self.mapHeight - 1:
							if self.terrain[i-self.mapWidth] == self.terrainGrass:
								self.terrain[i-self.mapWidth] = self.terrainPlains
							if self.terrain[i+self.mapWidth] == self.terrainGrass:
								self.terrain[i+self.mapWidth] = self.terrainPlains
							if self.terrain[i-1] == self.terrainGrass:
								self.terrain[i-1] = self.terrainPlains
							if self.terrain[i+1] == self.terrainGrass:
								self.terrain[i+1] = self.terrainPlains

	def getArcticTerrain(self, climate, latitude, moisture):
		polar = 0
		if (latitude > 70):
			polar = latitude - 70
			climate.ice += polar * polar * 3
			climate.tundra += polar * (2 + moisture)

	def getColdTerrain(self, climate, latitude, moisture):
		if (latitude > 60):
			polar = latitude - 60
			climate.tundra += polar * (5 + moisture) + self.dice.get(polar*3,"more tundra")
			if (moisture > 10):
				climate.plains += polar * (moisture - 10)

	def getTemperateTerrain(self, climate, latitude, moisture):
		temperate = 45 - abs(45 - latitude)
		climate.plains += temperate * (3 + moisture/2)
		climate.grass += temperate * (1 + moisture) + self.dice.get(temperate,"more grass")

	def getTropicalTerrain(self, climate, latitude, moisture):
		tropical = 0
		if (latitude < 40):
			tropical = 20 - abs(20 - latitude)
		climate.plains += tropical * (12 - self.climate + moisture/2) + self.dice.get(tropical,"more plains")
		climate.grass += tropical * (moisture + self.climate)
		climate.desert += tropical * (4 - self.climate) * 6

	def getEquatorialTerrain(self, climate, latitude, moisture):
		equator = 0
		if (latitude < 25):
			equator = 25 - latitude
		climate.plains += equator * 7
		climate.grass += equator * (3 + moisture) + self.dice.get(equator,"more grass")

	#I compute latitude as in the maputil but wtf is there a plot.latitude then?
	def getTerrain(self, latitude, moisture):
		class climates:
			def __init__(self):
				self.ice = 0
				self.tundra = 0
				self.plains = 0
				self.grass = 0
				self.desert = 0

		climate = climates()
		self.getArcticTerrain(climate, latitude, moisture)
		self.getColdTerrain(climate, latitude, moisture)
		self.getTemperateTerrain(climate, latitude, moisture)
		self.getTropicalTerrain(climate, latitude, moisture)
		self.getEquatorialTerrain(climate, latitude, moisture)

		if (climate.ice >= climate.tundra) and (climate.ice >= climate.plains) and (climate.ice >= climate.grass) and (climate.ice >= climate.desert):
			return self.terrainIce
		if (climate.tundra >= climate.plains) and (climate.tundra >= climate.grass) and (climate.tundra >= climate.desert):
			return self.terrainTundra
		if (climate.plains >= climate.grass) and (climate.plains >= climate.desert):
			return self.terrainPlains
		if (climate.grass >= climate.desert):
			return self.terrainGrass
		return self.terrainDesert

	def blowWinds(self):
	#Must find where the wind blows from and add moisture from there.
	#If there is a mountain in between, then terrain must become more arid:
	# Tundra -> ice (mmmh?), and grass -> plain -> desert.
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				if (self.map.plot(x,y).isWater()):
					self.windBlowsFrom(x,y)

	def windBlowsFrom(self,x,y):
		latitude = self.getLatitudeAtPlot(x,y)
		horizontal = 0
		if (latitude > 80):
			horizontal = 1
		elif (latitude > 45):
			horizontal = -1
		elif (latitude > 30):
			horizontal = 1
		elif (latitude > 10):
			horizontal = -1
		else:
			horizontal = 1
		vertical = self.getVerticalWind(latitude,y)
		windForce = 1 + self.dice.get(self.maxWindForce,"Wind force")
		localMoisture = 5 + self.maxWindForce
		self.blow(localMoisture,windForce,horizontal,vertical,x,y)

	def getVerticalWind(self,latitude,y):
		if (latitude>70):
			vertical = -1
		elif (latitude>30):
			vertical = 1
		else:
			vertical = -1
		if (2*y < self.mapHeight):
			vertical *= -1
		return vertical

	def blow(self,localMoisture,maxHorizontal,horizontal,vertical,x,y):
		plotType = self.map.plot(x,y).getPlotType()
		if (y+vertical > 0 and y+vertical < self.mapHeight):
			if (plotType != PlotTypes.PLOT_PEAK):
				if (plotType == PlotTypes.PLOT_HILLS):
					self.blow(localMoisture - 7,maxHorizontal-2,horizontal,vertical,x,y+vertical)
				else:
					self.blow(localMoisture - 1,maxHorizontal-2,horizontal,vertical,x,y+vertical)
		for i in range(-1,maxHorizontal):
			adjustedX = x + i*horizontal
			if (adjustedX < 0):
				adjustedX += self.mapWidth
			elif (adjustedX >= self.mapWidth):
				adjustedX -= self.mapWidth
			self.moisture[y*self.mapWidth + adjustedX] = self.moisture[y*self.mapWidth + adjustedX] + localMoisture
			plotType = self.map.plot(adjustedX,y).getPlotType()
			if (plotType == PlotTypes.PLOT_PEAK):
				return
			elif (plotType == PlotTypes.PLOT_HILLS):
				localMoisture -= 7
			else:
				localMoisture -= 1
			if (localMoisture <= 0):
				return

	def blur(self):
		max = 1
		for y in range(self.mapHeight):
			for x in range(self.mapWidth):
				i = y*self.mapWidth + x
				if (max < self.moisture[i]):
					max = self.moisture[i]
		for y in range(1,self.mapHeight-2):
			for x in range(self.mapWidth):
				i = y*self.mapWidth + x
				self.moisture[i] = self.moisture[i]*100/max

#
# Main landmass/landscape generation function
#
def generatePlotTypes():
	"Generates a map with several continents and a few islands."
	print "-- generatePlotTypes()"
	numPlayers = gc.getGame().countCivPlayersEverAlive()
	surface = gc.getMap().getGridWidth() * gc.getMap().getGridHeight()
	numPlayers = (numPlayers + surface / 400) / 2
	numContinents = 1
	numSeaPlates = 1
	hotspotsFrequency = 900
	if (mapOptionLandmass == 0):       #                 "Earthlike (70% water)"
		numContinents = 1 + numPlayers*2
		numSeaPlates = numPlayers*3 - 1
		hotspotsFrequency = 900
		generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
	elif (mapOptionLandmass == 1):       #               "Continental (60% water)"
		numContinents = 1 + numPlayers*5/2
		numSeaPlates = numPlayers*5/2 - 1
		hotspotsFrequency = 1100
		generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
	elif (mapOptionLandmass == 3):     #                 "Lakes (30% water")
		numContinents = 1 + numPlayers*5
		numSeaPlates = numPlayers - 1
		hotspotsFrequency = 1900
		generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
	elif (mapOptionLandmass == 2):     #                 "Pangaea"
		generator = voronoiPangaeaMap(numPlayers)
	elif (mapOptionLandmass == 4):     #                 "Islands (85% Water)"
		numContinents = 1 + numPlayers
		numSeaPlates = numPlayers*6 - 1
		hotspotsFrequency = 700
		generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
	elif (mapOptionLandmass == 5):     #                 "Mediterranean"
		generator = voronoiMediterraneanMap(numPlayers)
	elif (mapOptionLandmass == 6 or mapOptionLandmass == 7): # "Terra"
		generator = voronoiTerraMap()
	plotTypes = generator.generate()
	# Print plotMap and differencePlotMap
	mst.mapPrint.buildPlotMap( True, "generatePlotTypes()", data=plotTypes )
	if mapOptionLandscape == 0:			# option Planetfall Highlands
		# 'Planetfall' uses ridges/highlands, the original Planetfall landscape generator will be used
		plotTypes = planetfallGenerateHighlands( plotTypes )
	elif mapOptionLandscape == 1:		# option Tectonic Highlands
		# 'Planetfall' uses ridges/highlands, some hills and peaks will be added
		plotTypes = mst.planetFallMap.buildPfallHighlands( data=plotTypes )
	return plotTypes

# Generate highland terrain for Planetfall - from planetfall.py mostly
def planetfallGenerateHighlands( plotTypes ):
	print "-- planetfallGenerateHighlands()"

	NiTextOut("Setting Plot Types (Python PlanetFall Highlands) ...")
	#-------------------------------------------------------------------------
	# Finetuning Constants
	#
	# Amount of Highlands.
	# Range [1, 100] (I think)
	# Higher number means LESS.
	h_highlands = 60
	# Lower grain will i.g. produce more coherent areas.
	# Range [1, ->].
	# Values below 4 are likey to produce just one big blobb...
	h_grain = 4
	# Amount of Peaks. Is derived from amount of highlands, hence as fraction
	# Range [0, 1]
	# 0 ~ no Peaks. 1 will probably cover all the map with them.
	# Here more means more. Sorry.
	h_peaks = 0.25

	iW = map.getGridWidth()
	iH = map.getGridHeight()
#	plotTypes = [PlotTypes.PLOT_OCEAN] * (iW*iH)
	terrainFrac = CyFractal()

#	fractal_world = PFHL_MultilayeredFractal()
#	plotTypes = fractal_world.generatePlotsByRegion()
	terrainFrac.fracInit(iW, iH, h_grain, dice, 0, -1, -1)

	iHighlandThreshold = terrainFrac.getHeightFromPercent(h_highlands)
	iPeaksThreshold = iHighlandThreshold - (iHighlandThreshold * h_peaks)

	# Now the main loop, which will assign the plot types.
	for x in range(iW):
		for y in range(iH):
			i = y*iW + x
			val = terrainFrac.getHeight(x,y)
			if plotTypes[i] == PlotTypes.PLOT_OCEAN:
				continue # Water plots already set.
			if val >= iHighlandThreshold:
				plotTypes[i] = PlotTypes.PLOT_HILLS
			elif val >= iPeaksThreshold and val < iHighlandThreshold:
				plotTypes[i] = PlotTypes.PLOT_PEAK
			else:
				pass
	return plotTypes

#Rivers map second try...
class riversMap:
	def __init__(self):
		self.gc = CyGlobalContext()
		self.dice = gc.getGame().getMapRand()
		self.map = CyMap()
		self.mapWidth = self.map.getGridWidth()
		self.mapHeight = self.map.getGridHeight()
		self.file = open( "d:\\tmp\\toto.txt", 'w' )
		self.generateHeightMap()

	def initHeightMap(self,currentLands):
		#initialize with high altitudes on peaks and hills
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				plot = self.map.plot(x,y)
				if (plot.getPlotType() == PlotTypes.PLOT_PEAK):
					currentLands[x + y*self.mapWidth]  = 1
					self.heightMap[x + y*self.mapWidth]  = 10000
				elif (plot.getPlotType() == PlotTypes.PLOT_HILLS):
					currentLands[x + y*self.mapWidth]  = 1
					self.heightMap[x + y*self.mapWidth]  = 1000
				elif (plot.getPlotType() == PlotTypes.PLOT_LAND):
					currentLands[x + y*self.mapWidth]  = 1
					self.heightMap[x + y*self.mapWidth]  = 1

	def generateHeightMap(self):
		self.heightMap = [0] * (self.mapWidth*self.mapHeight)
		currentLands = [0] * (self.mapWidth*self.mapHeight)
		self.initHeightMap(currentLands)
		finished = false
		#make sure there's a slope towards seas and lakes
		while not finished:
			finished = true
			buffer = [1] * (self.mapWidth*self.mapHeight)
			for x in range(self.mapWidth):
				for y in range(self.mapHeight):
					plot = x + y*self.mapWidth
					if currentLands[plot] == 0:
						buffer[plot] = 0
						for i in self.neighbours(x, y):
							buffer[i] = 0
			for x in range(self.mapWidth):
				for y in range(self.mapHeight):
					plot = x + y*self.mapWidth
					currentLands[plot] = buffer[plot]
					if buffer[plot] == 1:
						finished = false
						self.heightMap[plot] = 1 + self.heightMap[plot]
		#make sure there's a slope going downwards away from mountains
		for i in range(20):
			increase = []
			for x in range(self.mapWidth):
				for y in range(self.mapHeight):
					if self.heightMap[x + y*self.mapWidth] > 20 - i:
						for j in self.neighbours(x, y):
							increase.append(j)
			for plot in increase:
				self.heightMap[plot] = self.heightMap[plot] + 2
		for y in range(self.mapHeight):
			for x in range(self.mapWidth):
				plot = x + y*self.mapWidth
				self.file.write( str( self.heightMap[plot] ) + "\t" )
			self.file.write( "\n" )

	def neighbours(self, x, y):
		result = []
		if x == 0:
			result.append(y*self.mapWidth)
		else:
			result.append(x-1 + y*self.mapWidth)
		if x == self.mapWidth - 1:
			result.append(y*self.mapWidth)
		else:
			result.append(x+1 + y*self.mapWidth)
		if y > 0:
			result.append(x + (y-1)*self.mapWidth)
		if y < self.mapHeight - 1:
			result.append(x + (y+1)*self.mapWidth)
		return result

	def seedRivers(self):
		climate = mapOptionAridity
		if (climate == 0):                 # Arid
			divider = 6
		elif (climate == 1):               # Normal
			divider = 3
		elif (climate == 2):               # Wet
			divider = 2
		elif (climate == 3):               # No ice
			divider = 3
		probability = 30/divider
		seeds = []
		for x in range(self.mapWidth):
			for y in range(self.mapHeight):
				plot = self.map.plot(x,y)
				if (plot.getPlotType() == PlotTypes.PLOT_HILLS):
					if self.dice.get(100,"Start river") < probability:
						seeds.append( plot )
				elif (plot.getPlotType() == PlotTypes.PLOT_LAND):
					if self.dice.get(1000,"Start river in flatland") < probability + self.heightMap[x + y*self.mapWidth]:
						seeds.append( plot )
		for plot in seeds:
			riverID = self.gc.getMap().getNextRiverID()
			self.startRiver(riverID, plot)
		self.file.close()

	def startRiver(self, riverID, plot):
		if plot.isWater():
			return true
		x = plot.getX()
		y = plot.getY()
		height = self.heightMap[x + y * self.mapWidth]
		ns = self.checkNorthSouth(x, y, height)
		ew = self.checkEastWest(x, y, height)
		if ns == CardinalDirectionTypes.NO_CARDINALDIRECTION and ew == CardinalDirectionTypes.NO_CARDINALDIRECTION:
			self.file.write( "End river false\n" )
			return false
		self.file.write( "Will flow\n" )
		if ns != CardinalDirectionTypes.NO_CARDINALDIRECTION and ew != CardinalDirectionTypes.NO_CARDINALDIRECTION:
			if self.dice.get(self.mapHeight + self.mapWidth,"direction") < self.mapHeight:
				self.flow(riverID, plot, ns)
			else:
				self.flow(riverID, plot, ew)
		elif ns != CardinalDirectionTypes.NO_CARDINALDIRECTION:
			self.flow(riverID, plot, ns)
		elif ew != CardinalDirectionTypes.NO_CARDINALDIRECTION:
			self.flow(riverID, plot, ew)
		self.file.write( "End river true\n" )
		return true

	#checks for isWOfRiver
	def checkNorthSouth(self, x, y, height):
		if x == self.mapWidth - 1:
			delta = 1 - self.mapWidth
		else:
			delta = 1
		west = x + delta + y*self.mapWidth
		northSouthHeight = height + self.heightMap[west]
		result = CardinalDirectionTypes.NO_CARDINALDIRECTION
		plot = self.map.plot(x,y)
		if plot.isWOfRiver():
			return result
		if y > 0:
			nHeight = self.heightMap[x + (y-1)*self.mapWidth] + self.heightMap[x + delta + (y-1)*self.mapWidth]
			self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(nHeight) + " <? " + str(northSouthHeight) + "\n" )
			if nHeight < northSouthHeight:
				result = CardinalDirectionTypes.CARDINALDIRECTION_SOUTH
		if y < self.mapHeight -1:
			sHeight = self.heightMap[x + (y-1)*self.mapWidth] + self.heightMap[x + delta + (y-1)*self.mapWidth]
			self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(sHeight) + " <? " + str(northSouthHeight) + "\n" )
			if sHeight < northSouthHeight:
				if result == CardinalDirectionTypes.NO_CARDINALDIRECTION or sHeight < nHeight:
					result = CardinalDirectionTypes.CARDINALDIRECTION_NORTH
		return result

	#checks for isNOfRiver
	def checkEastWest(self, x, y, height):
		result = CardinalDirectionTypes.NO_CARDINALDIRECTION
		plot = self.map.plot(x,y)
		if plot.isNOfRiver():
			return result
		if y < self.mapHeight -1:
			south = x + (y+1)*self.mapWidth
			eastWestHeight = height + self.heightMap[south]
			if x == self.mapWidth - 1:
				west = y*self.mapWidth
				swest = (y+1)*self.mapWidth
			else:
				west = x + 1 + y*self.mapWidth
				swest = x + 1 + (y+1)*self.mapWidth
			wHeight = self.heightMap[west] + self.heightMap[swest]
			self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(wHeight) + " <? " + str(eastWestHeight) + "\n" )
			if wHeight < eastWestHeight:
				result = CardinalDirectionTypes.CARDINALDIRECTION_WEST
			if x == 0:
				east = y*self.mapWidth
				seast = (y+1)*self.mapWidth
			else:
				east = x - 1 + y*self.mapWidth
				seast = x - 1 + (y+1)*self.mapWidth
			eHeight = self.heightMap[east] + self.heightMap[seast]
			self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(eHeight) + " <? " + str(eastWestHeight) + "\n" )
			if eHeight < eastWestHeight:
				if result == CardinalDirectionTypes.NO_CARDINALDIRECTION or eHeight < wHeight:
					result = CardinalDirectionTypes.CARDINALDIRECTION_EAST
		return result

	def joins(self, riverPlot, riverID):
		return (riverPlot.isWOfRiver() or riverPlot.isNOfRiver()) and riverPlot.getRiverID() != riverID

	def flow(self, riverID, plot, direction):
		x = plot.getX()
		y = plot.getY()
		self.file.write( "Flow to " + str(x) + ", " + str(y) + "\n" )
		if direction == CardinalDirectionTypes.CARDINALDIRECTION_EAST:
			if x < self.mapWidth - 1:
				riverPlot = self.map.plot(x+1,y)
				if y == self.mapHeight - 1 or self.map.plot(x+1,y+1).isWater() or riverPlot.isWater():
					return
			else:
				riverPlot = self.map.plot(0,y)
				if y == self.mapHeight - 1 or self.map.plot(0,y+1).isWater() or riverPlot.isWater():
					return
			joinRiver = self.joins(riverPlot, riverID)
			riverPlot.setNOfRiver(True,direction)
		if direction == CardinalDirectionTypes.CARDINALDIRECTION_WEST:
			if x > 0:
				riverPlot = self.map.plot(x-1,y)
				if y == self.mapHeight - 1 or self.map.plot(x-1,y+1).isWater() or riverPlot.isWater():
					return
			else:
				riverPlot = self.map.plot(self.mapWidth-1,y)
				if y == self.mapHeight - 1 or self.map.plot(self.mapWidth-1,y+1).isWater() or riverPlot.isWater():
					return
			joinRiver = self.joins(riverPlot, riverID)
			riverPlot.setNOfRiver(True,direction)
		if direction == CardinalDirectionTypes.CARDINALDIRECTION_NORTH:
			riverPlot = self.map.plot(x,y-1)
			if ( x == self.mapWidth - 1 and self.map.plot(0,y).isWater() ) or ( x < self.mapWidth - 1 and self.map.plot(x+1,y).isWater() ) or riverPlot.isWater():
				return
			joinRiver = self.joins(riverPlot, riverID)
			riverPlot.setWOfRiver(True,direction)
		if direction == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH:
			riverPlot = self.map.plot(x,y+1)
			if ( x == self.mapWidth - 1 and self.map.plot(0,y).isWater() ) or ( x < self.mapWidth - 1 and self.map.plot(x+1,y).isWater() ) or riverPlot.isWater():
				return
			joinRiver = self.joins(riverPlot, riverID)
			riverPlot.setWOfRiver(True,direction)
		if joinRiver:
			self.file.write( "Joining rivers\n" )
			return
		riverPlot.setRiverID(riverID)
		self.startRiver(riverID,riverPlot)
		#if not self.startRiver(riverID,riverPlot):
			#self.file.write( "Add ocean in " + str(riverPlot.getX()) + ", " + str(riverPlot.getY()) + "\n" )
			#riverPlot.setPlotType(PlotTypes.PLOT_OCEAN,true,true)

# This whole class is needlessly complex. It would be better to rewrite it by first defining
# a new map, which is the map of the places between squares, giving them an altitude which would be the max
# of the surrounding squares. This would simplify this a lot but I'm too lazy for now to rewrite all.
class riversFromSea:
	def __init__(self):
		self.gc = CyGlobalContext()
		self.dice = self.gc.getGame().getMapRand()
		self.map = CyMap()
		self.width = self.map.getGridWidth()
		self.height = self.map.getGridHeight()
		self.straightThreshold = 4
		self.riverLength = {}
		self.riverTurns = {}
		self.minRiverLength = self.height/6
		if (self.width * self.height > 400):
			self.straightThreshold = 3

	def seedRivers(self):
		climate = mapOptionAridity
		if (climate == 0):                 # Arid
			divider = 4
		elif (climate == 1):               # Normal
			divider = 2
		elif (climate == 2):               # Wet
			divider = 1
		elif (climate == 3):               # No ice
			divider = 2
		maxNumber = (self.width + self.height) / divider
		riversNumber = 1 + maxNumber
		if (mapOptionLandmass == 1):       # Pangaea
			riversNumber = maxNumber/2
		self.coasts = self.collateCoasts()
		coastsNumber = len(self.coasts)
		if (coastsNumber == 0):
			return
		coastShare = coastsNumber/riversNumber
		for i in range(riversNumber):
			flow = CardinalDirectionTypes.NO_CARDINALDIRECTION
			tries = 0
			while flow == CardinalDirectionTypes.NO_CARDINALDIRECTION and tries < 6:
				tries = tries + 1
				(x,y,flow) = self.generateRiver(i,coastShare)
			if flow != CardinalDirectionTypes.NO_CARDINALDIRECTION:
				riverID = self.gc.getMap().getNextRiverID()
				self.riverLength[riverID] = 0
				self.riverTurns[riverID] = 0
				self.addRiverFrom(x,y,flow,riverID)

	def collateCoasts(self):
		result = []
		for x in range(self.width):
			for y in range(self.height):
				plot = self.map.plot(x,y)
				if (plot.isCoastalLand()):
					result.append(plot)
		return result

	def generateRiver(self,i,coastShare):
		choiceCoast = coastShare * i + self.dice.get(coastShare,"Pick a coast for the river")
		plot = self.coasts[choiceCoast]
		FlowDirection = CardinalDirectionTypes.NO_CARDINALDIRECTION
		x = plot.getX()
		y = plot.getY()
		if ((y < 1 or y >= self.height - 1) or plot.isNOfRiver() or plot.isWOfRiver()):
			return (x,y,FlowDirection)
		eastX = self.eastX(x)
		westX = self.westX(x)
		otherPlot = True
		eastPlot = self.map.plot(eastX,y)
		if (eastPlot.isCoastalLand()):
			seaPlot = self.map.plot(x,y+1)
			if ((self.map.plot(x,y+1).isWater()) or (self.map.plot(eastX,y+1).isWater())):
				landPlot1 = self.map.plot(x,y-1)
				landPlot2 = self.map.plot(eastX,y-1)
				if (landPlot1.isWater() or landPlot2.isWater()):
					otherPlot = True
				else:
					FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_NORTH
					otherPlot = False
			if (otherPlot == True):
				if ((self.map.plot(x,y-1).isWater()) or (self.map.plot(eastX,y-1).isWater())):
					landPlot1 = self.map.plot(x,y+1)
					landPlot2 = self.map.plot(eastX,y+1)
					if (landPlot1.isWater() or landPlot2.isWater()):
						otherPlot = True
					else:
						FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_SOUTH
						otherPlot = False
		if (otherPlot == True):
			southPlot = self.map.plot(x,y-1)
			if (southPlot.isCoastalLand()):
				if ((self.map.plot(eastX,y).isWater()) or (self.map.plot(eastX,y-1).isWater())):
					landPlot1 = self.map.plot(westX,y)
					landPlot2 = self.map.plot(westX,y-1)
					if (landPlot1.isWater() or landPlot2.isWater()):
						otherPlot = True
					else:
						FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_EAST
						otherPlot = False
				if (otherPlot == True):
					if ((self.map.plot(westX,y).isWater()) or (self.map.plot(westX,y-1).isWater())):
						landPlot1 = self.map.plot(eastX,y)
						landPlot2 = self.map.plot(eastX,y-1)
						if (landPlot1.isWater() or landPlot2.isWater()):
							otherPlot = True
						else:
							FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_WEST
		return (x,y,FlowDirection)

	# prevent rivers from crossing each other
	def preventRiversFromCrossing(self,x,y,flow,riverID):
		plot = self.map.plot(x,y)
		eastX = self.eastX(x)
		westX = self.westX(x)
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
			if (plot.isNOfRiver()):
				return true
			if (self.map.plot(eastX,y).isNOfRiver()):
				return true
			southPlot = self.map.plot(x,y-1)
			if (southPlot.isWOfRiver() and southPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
				return true
			if (plot.isWOfRiver() and plot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
				return true
			if (self.map.plot(eastX,y).isWater()):
				return true
			if (self.map.plot(x,y-1).isWater()):
				return true
			if (self.map.plot(eastX,y-1).isWater()):
				return true
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
			if (plot.isNOfRiver()):
				return true
			if (self.map.plot(westX,y).isNOfRiver()):
				return true
			southPlot = self.map.plot(westX,y-1)
			if (southPlot.isWOfRiver() and southPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
				return true
			westPlot = self.map.plot(westX,y)
			if (westPlot.isWOfRiver() and westPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
				return true
			if (self.map.plot(westX,y).isWater()):
				return true
			if (self.map.plot(x,y-1).isWater()):
				return true
			if (self.map.plot(westX,y-1).isWater()):
				return true
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
			if (plot.isWOfRiver()):
				return true
			eastPlot = self.map.plot(eastX,y)
			if (eastPlot.isNOfRiver() and eastPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
				return true
			if (plot.isNOfRiver() and plot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
				return true
			if (self.map.plot(x,y-1).isWOfRiver()):
				return true
			if (self.map.plot(x,y-1).isWater()):
				return true
			if (self.map.plot(x+1,y).isWater()):
				return true
			if (self.map.plot(x+1,y-1).isWater()):
				return true
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
			if (plot.isWOfRiver()):
				return true
			eastPlot = self.map.plot(eastX,y+1)
			if (eastPlot.isNOfRiver() and eastPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
				return true
			northPlot = self.map.plot(x,y+1)
			if (northPlot.isNOfRiver() and northPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
				return true
			if (self.map.plot(x,y+1).isWOfRiver()):
				return true
			if (self.map.plot(x,y+1).isWater()):
				return true
			if (self.map.plot(x+1,y).isWater()):
				return true
			if (self.map.plot(x+1,y+1).isWater()):
				return true
		return false


	def addRiverFrom(self,x,y,flow,riverID):
		plot = self.map.plot(x,y)
		if (plot.isWater()):
			return
		self.riverLength[riverID] = self.riverLength[riverID] + 1
		eastX = self.eastX(x)
		westX = self.westX(x)
		if (self.preventRiversFromCrossing(x,y,flow,riverID)):
			return
		plot.setRiverID(riverID)
		if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
			plot.setNOfRiver(True,flow)
		else:
			plot.setWOfRiver(True,flow)
		xShift = 0
		yShift = 0
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
			xShift = 1
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
			xShift = -1
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
			yShift = -1
		if (flow == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
			yShift = 1
		nextX = x + xShift
		nextY = y + yShift
		if (nextX >= self.width):
			nextX = 0
		if (nextY >= self.height):
			return
		nextI = nextY*self.width + nextX
		if (self.canFlowFrom(plot,self.map.plot(nextX,nextY)) == False):
			return
		if not mst.bPfall and plot.getTerrainType() == mst.etSnow and self.dice.get(10,"Stop on ice") > 3:
			return
		if mst.bPfall and (plot.getTerrainType() == mst.etFlatPolar or plot.getTerrainType() == mst.etRockyPolar) and self.dice.get(10,"Stop on ice") > 3:
			return
		flatDesert = plot.getPlotType() == PlotTypes.PLOT_LAND and \
		             ((not mst.bPfall and plot.getTerrainType() == mst.etDesert) or\
		              (mst.bPfall and (plot.getTerrainType() == mst.etFlatArid or plot.getTerrainType() == mst.etRockyArid)))
		#Prevent Uturns in rivers
		turnThreshold = 13
		if flatDesert:
			turnThreshold = 17
		turned = False
		northY = y + 1
		southY = y - 1
		if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
			if ((northY < self.height) and (self.dice.get(20,"branch from north") > turnThreshold)):
				nextI = northY*self.width + x
				if (self.canFlowFrom(plot,self.map.plot(x,northY)) and self.canFlowFrom(self.map.plot(self.eastX(x),y),self.map.plot(self.eastX(x),northY))):
					turned = True
					self.riverTurns[riverID] = self.riverTurns[riverID] + 1
					if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
						self.addRiverFrom(x,y,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH,riverID)
					else:
						westPlot = self.map.plot(westX,y)
						westPlot.setRiverID(riverID)
						self.addRiverFrom(westX,y,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH,riverID)
			if ((not turned) and (southY >= 0) and (self.dice.get(20,"branch from south") > turnThreshold)):
				nextI = southY*self.width + x
				if (self.canFlowFrom(plot,self.map.plot(x,southY)) and self.canFlowFrom(self.map.plot(self.eastX(x),y),self.map.plot(self.eastX(x),southY))):
					turned = True
					self.riverTurns[riverID] = self.riverTurns[riverID] + 1
					if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
						southPlot = self.map.plot(x,y-1)
						southPlot.setRiverID(riverID)
						self.addRiverFrom(x,southY,CardinalDirectionTypes.CARDINALDIRECTION_NORTH,riverID)
					else:
						westPlot = self.map.plot(westX,southY)
						westPlot.setRiverID(riverID)
						self.addRiverFrom(westX,southY,CardinalDirectionTypes.CARDINALDIRECTION_NORTH,riverID)
		else:
			nextI = y*self.width + eastX
			if (self.canFlowFrom(plot,self.map.plot(eastX,y)) and self.canFlowFrom(self.map.plot(x,southY),self.map.plot(eastX,y)) and (self.dice.get(20,"branch from east") > turnThreshold)):
				turned = True
				self.riverTurns[riverID] = self.riverTurns[riverID] + 1
				if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
					eastPlot = self.map.plot(eastX,y)
					eastPlot.setRiverID(riverID)
					self.addRiverFrom(eastX,y,CardinalDirectionTypes.CARDINALDIRECTION_WEST,riverID)
				else:
					northEastPlot = self.map.plot(eastX,y+1)
					northEastPlot.setRiverID(riverID)
					self.addRiverFrom(eastX,y+1,CardinalDirectionTypes.CARDINALDIRECTION_WEST,riverID)
			nextI = y*self.width + westX
			if ((not turned) and self.canFlowFrom(plot,self.map.plot(westX,y)) and self.canFlowFrom(self.map.plot(x,southY),self.map.plot(westX,southY)) and (self.dice.get(20,"branch from west") > turnThreshold)):
				turned = True
				if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
					self.addRiverFrom(x,y,CardinalDirectionTypes.CARDINALDIRECTION_EAST,riverID)
				else:
					northPlot = self.map.plot(x,y+1)
					northPlot.setRiverID(riverID)
					self.addRiverFrom(x,y+1,CardinalDirectionTypes.CARDINALDIRECTION_EAST,riverID)
		spawnInDesert = (not turned) and flatDesert
		if ((self.dice.get(10,"straight river") > self.straightThreshold) or spawnInDesert):
			if (not turned) or (self.riverTurns[riverID] * 5 < self.riverLength[riverID]):
				self.addRiverFrom(nextX,nextY,flow,riverID)
		else:
			if (not turned):
				if self.riverLength[riverID] < self.minRiverLength:
					self.addRiverFrom(nextX,nextY,flow,riverID)
				else:
					plot = self.map.plot(nextX,nextY)
					if ((plot.getPlotType() == PlotTypes.PLOT_LAND) and (self.dice.get(10,"Rivers start in hills") > 3)):
						plot.setPlotType(PlotTypes.PLOT_HILLS,true,true)
						if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
							if southY > 0:
								self.map.plot(nextX,southY).setPlotType(PlotTypes.PLOT_HILLS,true,true)
						else:
							self.map.plot(eastX,nextY).setPlotType(PlotTypes.PLOT_HILLS,true,true)

	def canFlowFrom(self,plot,upperPlot):
		if (plot.isWater()):
			return False
		if (plot.getPlotType() == PlotTypes.PLOT_PEAK):
			return False
		if (plot.getPlotType() == PlotTypes.PLOT_HILLS):
			if ((upperPlot.getPlotType() == PlotTypes.PLOT_HILLS) or (upperPlot.getPlotType() == PlotTypes.PLOT_PEAK)):
				return True
			else:
				return False
		if (plot.getPlotType() == PlotTypes.PLOT_LAND):
			if (upperPlot.isWater()):
				return False
		return True

	def westX(self,x):
		westX = x - 1
		if (westX < 0):
			westX = self.width
		return westX

	def eastX(self,x):
		eastX = x + 1
		if (eastX >= self.width):
			eastX = 0
		return eastX

# ------------------------------
# Temudjins Cool Starting Plots
# ------------------------------
# ensures that there are more than 3 land/hill plots within the central 3x3 grid
# and more than ok land/hill plots in the 5x5 grid around the starting-plot
def okLandPlots(xCoord, yCoord, ok=10):
	land1 = 0
	if ok >= 0:
		for x in range( -2, 3 ):
			for y in range( -2, 3 ):
				plot = plotXY( xCoord, yCoord, x, y )
				if not plot.isNone():
					if plot.isHills() or plot.isFlatlands():
						land1 += 1
		if land1 > ok:
			land2 = 0
			for x in range( -1, 2 ):
				for y in range( -1, 2 ):
					plot = plotXY( xCoord, yCoord, x, y )
					if not plot.isNone():
						if plot.isHills() or plot.isFlatlands():
							land2 += 1
			if land2 > 3:
				return True
	return False

# ensures that plot isn't within ok plots from edge of the world
def okMapEdge( x, y, ok=3 ):
	if not map.isWrapX():
		if ( x < ok ) or ( x > (mst.iNumPlotsX-1-ok) ):
			return False
	if not map.isWrapY():
		if ( y < ok ) or ( y > (mst.iNumPlotsY-1-ok) ):
			return False
	return True
# ----------------------------------
# END Temudjin's Cool Starting Plots
# ----------------------------------

# ######################################################################################################
# ######## assignStartingPlots() - Called from system
# ######## - assign starting positions for each player after the map is generated
# ######## - Planetfall has GameOption 'SCATTERED_LANDING_PODS' - use default implementation
# ######################################################################################################
def assignStartingPlots():
	iPlayers = gc.getGame().countCivPlayersEverAlive()
	if mst.bPfall:
		CyPythonMgr().allowDefaultImpl()
	else:
		map.recalculateAreas()
		areas = CvMapGeneratorUtil.getAreas()
		areaValue = {}
		allOnBest = false
		isolatedStarts = false
		if (mapOptionLandmass == 4):     #                 "Islands"
			isolatedStarts = true
		if (mapOptionLandmass == 7):     #                 "Terra"
			allOnBest = true

		for area in areas:
			if area.isWater(): continue
			areaValue[area.getID()] = area.calculateTotalBestNatureYield() + area.getNumRiverEdges() + 2 * area.countCoastalLand() + 3 * area.countNumUniqueBonusTypes()

		# Shuffle players so the same player doesn't always get the first pick.
		player_list = []
		########## Temudjin START
		#for plrCheckLoop in range(18):
		for plrCheckLoop in range( gc.getMAX_CIV_PLAYERS() ):
		########## Temudjin END
			if gc.getPlayer(plrCheckLoop).isEverAlive():
				player_list.append(plrCheckLoop)
		shuffledPlayers = []
		for playerLoop in range(iPlayers):
			iChoosePlayer = dice.get(len(player_list), "Shuffling Players - Highlands PYTHON")
			shuffledPlayers.append(player_list[iChoosePlayer])
			del player_list[iChoosePlayer]

		# Loop through players, assigning starts for each.
		for assign_loop in range(iPlayers):
			playerID = shuffledPlayers[assign_loop]
			player = gc.getPlayer(playerID)
			if (allOnBest):
				#-----
				def isValid(playerID, x, y):
					pPlot = map.plot(x, y)
					if (pPlot.getArea() != map.findBiggestArea(False).getID()):
						return False
					########## Temudjin START
					#return True
					# Also check for Temudjin's cool starting plots
					return ( okLandPlots(x,y,10) and okMapEdge(x,y,3) )
					########## Temudjin END
				#-----
			else:
				bestAreaValue = 0
				global bestArea
				bestArea = -1
				for area in areas:
					if area.isWater(): continue
					players = 2*area.getNumStartingPlots()
					#Avoid single players on landmasses:
					if (false == isolatedStarts and players == 0):
						if (assign_loop == iPlayers - 1):
							players = 4
						else:
							players = 2
					value = areaValue[area.getID()] / (1 + 2*players )
					if (value > bestAreaValue):
						bestAreaValue = value;
						bestArea = area.getID()

				#-----
				def isValid(playerID, x, y):
					global bestArea
					plot = map.plot(x,y)
					if (plot.getArea() != bestArea):
						return false
					if (plot.getLatitude() >= 75):
						return false
					########## Temudjin START
					#return True
					# Also check for Temudjin's cool starting plots
					return ( okLandPlots(x,y,10) and okMapEdge(x,y,3) )
					########## Temudjin END
				#-----

			findstart = CvMapGeneratorUtil.findStartingPlot(playerID,isValid)
			sPlot = map.plotByIndex(findstart)
			player.setStartingPlot(sPlot,true)

class MediterraneanFeatureGenerator(CvMapGeneratorUtil.FeatureGenerator):
	def getLatitudeAtPlot(self, iX, iY):
		"returns 0.0 for tropical, up to 1.0 for polar"
		# 25/90 to 65/90:
		lat = 5/float(18) + 4*(self.iGridH - iY)/float(9*self.iGridH)
		return lat

class NoIceFeatureGenerator(CvMapGeneratorUtil.FeatureGenerator):
	def addIceAtPlot(self, pPlot, iX, iY, lat):
		return

def addFloodPlains(plot):
	if plot.isRiverSide() and plot.isFlatlands():
		if (plot.getFeatureType() == FeatureTypes.NO_FEATURE):
			for iI in range(gc.getNumFeatureInfos()):
				if plot.canHaveFeature(iI):
					if 10000 == gc.getFeatureInfo(iI).getAppearanceProbability():
						plot.setFeatureType(iI, -1)
