Tectonics_mst.py 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2005-2008 Laurent Di Cesare
  3. # Copyright (c) 2008 Firaxis Games, Inc. All rights reserved.
  4. #-----------------------------------------------------------------------------
  5. #
  6. # FILE: Tectonics.py
  7. # AUTHOR: Laurent Di Cesare (LDiCesare)
  8. # PURPOSE: Provide a map with mountain ranges, preferably near the coasts.
  9. # DESCRIPTION:
  10. # Provide a map with several continents, possibly some big islands,
  11. # and simulates some very rough plate tectonics to generate mountain ranges.
  12. # The map is tuned to generate about 40% land and 60% water but only the
  13. # number of plates is fixed, not the actual size of the plates, so landmasses
  14. # sizes may vary quite a bit.
  15. # It is an adaptation to CivIV of an algorithm originally developped for
  16. # the Clash of Civilizations (http://clash.apolyton.net)
  17. # VERSION 1.0 Initial version
  18. # VERSION 1.1 Changed the moveplates and blur routines to avoid having
  19. # big lumps of peaks propagating everywhere.
  20. # Added subduction
  21. # Hinted continents seeds to avoid the poles
  22. # VERSION 2.0 Added climate management.
  23. # VERSION 2.1 Made desert edges rougher.
  24. # Added first try at rivers.
  25. # Increased subduction
  26. # VERSION 3.0 Added various landmasses (Pangaeas, Lakes, Islands).
  27. # Modified rivers
  28. # VERSION 3.1 Lost when reinstalling windows and not backing it up.
  29. # It was great, though.
  30. # VERSION 3.2 Provided new option for Earthlike, and grouped land masses
  31. # so 2/3rds are on the same hemisphere. Less ice.
  32. # VERSION 3.3 Systematic use of climate map because I had bugged it away for
  33. # the main map type instead of pangaea. Tried to prevent players
  34. # from starting in the ice. Added hotspots.
  35. # VERSION 3.4 Minor rewritings.
  36. # Added fault lines: Some hills and lakes will pop up inside
  37. # vast flat areas, forming a ridge line, but with lots of flat
  38. # lands inside. Not always noticeable but has a definite effect.
  39. # Corrected climate generation which didn't blow enough moisture.
  40. # VERSION 3.5 Added several climate options. Tuned the starting locations.
  41. # VERSION 3.6 Roughed the edges of the various climate zones to avoid excess
  42. # of straight limits.
  43. # Added Mediterranean land type (inner sea).
  44. # Added No Ice option that replaces ice with tundra and tundra
  45. # with grass, otherwise behaves as normal humidity level.
  46. # VERSION 3.7 Mediterranean map rewrite: East is always land, more and bigger
  47. # islands, correct latitude used for feature generation.
  48. # VERSION 3.8 Fixed WrapY error.
  49. # VERSION 3.9 Fixed subduction error.
  50. # VERSION 3.10 Shapes of plates are somewhat less square, and rivers in desert
  51. # are always floodplains even after the default algorithm adds
  52. # them near players' starting location
  53. # VERSION 3.11 Climate generation rewritten, rivers less likely to start
  54. # in desert and more often from hills.
  55. # VERSION 3.12 Broke east-west climate lines, smoothed desert-grass
  56. # transitions always through plains.
  57. # VERSION 3.13 More mountains (second pass of movePlates). Terra option.
  58. # VERSION 3.14 Fixed starting plot generation errors.
  59. # VERSION 3.15 Added an option not to group civs on Terra option,
  60. # Tuned Terra landmasses (mostly Africa, Greenland), removed
  61. # Antarctic landmass (too many barbs spawning there).
  62. # VERSION 3.16 Included Firaxis code for translating the options.
  63. # Kept my copyrights.
  64. # Added more rivers. (Also aborted try at heghtmap for rivers.)
  65. # Updated the Terra option to have much better looking Arabia.
  66. # TODO The shape of the plates should be less polygonal and more random
  67. # (more round than rectangular)
  68. # The number of plates could be more tunable.
  69. # I could also rewrite the whole rivers thing...
  70. # Modified by Terkhen
  71. # VERSION 3.19_mst - 21.Sep.2016
  72. # - Fixed [Planetfall], do not use snow and desert terrain, use their Planetfall equivalents instead.
  73. #
  74. # Modified by Terkhen
  75. # VERSION 3.18_mst - 17.Aug.2016
  76. # - Fixed, use terrain, feature and improvement definitions from MST.
  77. #
  78. # Modified by Terkhen
  79. # VERSION 3.17_mst - 08.Dic.2014
  80. # - Added, save/load map options.
  81. # - Added, compatibility with RandomMap.
  82. # - Changed, resource balance option.
  83. # - Changed, use TXT strings instead of hardcoded ones.
  84. #
  85. # Modified by Temudjin
  86. # VERSION 3.16a_mst - 15.Mar.2011
  87. # - Fixed, the land/water percentages are somewhat more realistic now
  88. # - Fixed [Planetfall], tried to lumpify normal terrain in 'Planetfall'
  89. # - Fixed [Planetfall], now compatibile with Planetfalls' 'Scattered Pods' mod option
  90. # - Fixed [Mars Now!], team start normalization
  91. # - Added, new map option for expanded coastal waters (like Civ5)
  92. # - Added [Planetfall], option to use original Planetfall Highlands Generator
  93. # - Added [Mars Now!], new map option: 'Sands of Mars'/'Terraformed Mars'
  94. # - Changed, fewer rivers from lakes
  95. # - Changed, smaller maximum number of BigDent/BigBogs for Island/Terra options
  96. # - Changed, removed Whale boni for Lakes (30% Water) option
  97. # - Changed, stratified custom map option process
  98. # - Changed, stratified normalization process
  99. # - Changed, reorganised function call sequence within map building process
  100. # - Changed [Mars Now!], using dedicated terrain generator
  101. #
  102. # VERSION 3.16_mst - 15.Jul.2010
  103. # - use MapScriptTools
  104. # - compatibility with 'Planetfall'
  105. # - compatibility with 'Mars Now!'
  106. # - supports any number of players
  107. # - add Map Option: TeamStart
  108. # - add Marsh terrain, if supported by mod
  109. # - add Deep Ocean terrain, if supported by mod
  110. # - add rivers on islands
  111. # - allow more world sizes, if supported by mod
  112. # - add Map Features ( Kelp, HauntedLands, CrystalPlains )
  113. # - add Map Regions ( BigDent, BigBog, ElementalQuarter, LostIsle )
  114. # - better balanced resources
  115. # - check for Temudjin's Cool Starting Plots
  116. # - print stats of mod and map
  117. #
  118. from CvPythonExtensions import *
  119. import CvUtil
  120. import CvMapGeneratorUtil
  121. gc = CyGlobalContext()
  122. map = CyMap()
  123. dice = gc.getGame().getMapRand()
  124. ##################################################################################
  125. ## MapScriptTools Interface by Temudjin START
  126. ##################################################################################
  127. import MapScriptTools as mst
  128. balancer = mst.bonusBalancer
  129. # The following two functions are not exactly neccessary, but they should be
  130. # in all map-scripts. Just comment them out if they are already in the script.
  131. # ----------------------------------------------------------------------------
  132. def getVersion():
  133. return "3.19_mst"
  134. def getDescription():
  135. return "TXT_KEY_MAP_SCRIPT_TECTONICS_DESCR"
  136. # #################################################################################################
  137. # ######## randomMapBeforeInit() - Starts the map-generation process, called by RandomMap to set
  138. # ######## the map options
  139. # #################################################################################################
  140. def randomMapBeforeInit(moWorldShape, moResources, moCoastalWaters, moTeamStart, moMarsTheme):
  141. print "-- randomMapBeforeInit()"
  142. # Avoid errors while printing custom options.
  143. global op
  144. op = {}
  145. # Map options of this script
  146. global mapOptionLandmass, mapOptionAridity, mapOptionCoastalWaters, mapOptionResources
  147. global mapOptionLandscape, mapOptionTeamStart, mapOptionMarsTheme
  148. # Options chosen in Random Map
  149. mapOptionResources = moResources
  150. mapOptionCoastalWaters = moCoastalWaters
  151. mapOptionTeamStart = moTeamStart
  152. mapOptionMarsTheme = moMarsTheme
  153. # All other options are chosen randomly.
  154. mapOptionLandmass = CyGlobalContext().getGame().getMapRand().get(8, "Tectonics.randomMapBeforeInit(), mapOptionLandmass")
  155. mapOptionAridity = CyGlobalContext().getGame().getMapRand().get(4, "Tectonics.randomMapBeforeInit(), mapOptionAridity")
  156. mapOptionLandscape = mst.iif(mst.bPfall, CyGlobalContext().getGame().getMapRand().get(3, "Tectonics.randomMapBeforeInit(), mapOptionLandscape"), None)
  157. # #################################################################################################
  158. # ######## beforeInit() - Starts the map-generation process, called after the map-options are known
  159. # ######## - map dimensions, latitudes and wrapping status are not known yet
  160. # ######## - handle map specific options
  161. # #################################################################################################
  162. def beforeInit():
  163. print "-- beforeInit()"
  164. # Selected map options
  165. global mapOptionLandmass, mapOptionAridity, mapOptionCoastalWaters, mapOptionResources
  166. global mapOptionLandscape, mapOptionTeamStart, mapOptionMarsTheme
  167. mapOptionResources = map.getCustomMapOption(0)
  168. mapOptionLandmass = map.getCustomMapOption(1)
  169. mapOptionAridity = map.getCustomMapOption(2)
  170. mapOptionCoastalWaters = mst.iif(mst.bPfall, None, map.getCustomMapOption(3))
  171. mapOptionLandscape = mst.iif(mst.bPfall, map.getCustomMapOption(3), None)
  172. mapOptionTeamStart = mst.iif(mst.bMars, None, map.getCustomMapOption(4))
  173. mapOptionMarsTheme = mst.iif(mst.bMars, map.getCustomMapOption(4), None)
  174. # #######################################################################################
  175. # ######## beforeGeneration() - Called from system after user input is finished
  176. # ######## - define your latitude formula, get the map-version
  177. # ######## - create map options info string
  178. # ######## - initialize the MapScriptTools
  179. # ######## - initialize MapScriptTools.BonusBalancer
  180. # #######################################################################################
  181. def beforeGeneration():
  182. print "-- beforeGeneration()"
  183. # Create evaluation string for latitudes
  184. compGetLat = None
  185. if mapOptionLandmass == 5:
  186. compLat = "90 * ( 5/18.0 + 4*(%i-y) / (%i*9.0) )" % (map.getGridHeight(),map.getGridHeight())
  187. # Create mapInfo string
  188. mapInfo = ""
  189. # Backup current language
  190. iLanguage = CyGame().getCurrentLanguage()
  191. # Force english language for logs
  192. CyGame().setCurrentLanguage(0)
  193. for opt in range( getNumCustomMapOptions() ):
  194. nam = getCustomMapOptionName( [opt] )
  195. sel = map.getCustomMapOption( opt )
  196. txt = getCustomMapOptionDescAt( [opt,sel] )
  197. mapInfo += "%27s: %s\n" % ( nam, txt )
  198. # Restore current language
  199. CyGame().setCurrentLanguage(iLanguage)
  200. # Obtain the map options in use.
  201. lMapOptions = []
  202. for opt in range( getNumCustomMapOptions() ):
  203. iValue = 0 + map.getCustomMapOption( opt )
  204. lMapOptions.append( iValue )
  205. # Save used map options.
  206. mst.mapOptionsStorage.writeConfig(lMapOptions)
  207. # Initialize MapScriptTools
  208. mst.getModInfo( getVersion(), None, mapInfo )
  209. # Initialize MapScriptTools
  210. mst.getModInfo( getVersion(), compGetLat, mapInfo )
  211. # Determine global Mars Theme
  212. mst.bSandsOfMars = (mapOptionMarsTheme == 0)
  213. # Initialize MapScriptTools.BonusBalancer
  214. balancer.initialize( mapOptionResources == 1 ) # balance boni if desired, place missing boni, move minerals
  215. # #######################################################################################
  216. # ######## generateTerrainTypes() - Called from system after generatePlotTypes()
  217. # ######## - SECOND STAGE in 'Generate Map'
  218. # ######## - creates an array of terrains (desert,plains,grass,...) in the map dimensions
  219. # #######################################################################################
  220. def generateTerrainTypes():
  221. print "-- generateTerrainTypes()"
  222. # Planetfall: more highlands
  223. mst.planetFallMap.buildPfallHighlands()
  224. # Prettify the map - change coastal peaks to hills with 50% chance; default: 66%
  225. mst.mapPrettifier.hillifyCoast( 50 )
  226. # Prettify map: Connect small islands
  227. # mst.mapPrettifier.bulkifyIslands()
  228. # If your active mod is 'Planetfall'/'Mars Now!', you will have to use a different terrainGenerator.
  229. if mst.bPfall:
  230. terraingen = mst.MST_TerrainGenerator()
  231. elif mst.bMars:
  232. iDesert = mst.iif( mst.bSandsOfMars, 16, 32 )
  233. terraingen = mst.MST_TerrainGenerator_Mars( iDesert )
  234. else:
  235. # Normally use original Tectonics terrain-generator.
  236. terraingen = ClimateGenerator()
  237. # Create the terrain and return the result.
  238. terrainTypes = terraingen.generateTerrain()
  239. print "-- testtt"
  240. return terrainTypes
  241. # #######################################################################################
  242. # ######## addRivers() - Called from system after generateTerrainTypes()
  243. # ######## - THIRD STAGE in 'Generate Map'
  244. # ######## - puts rivers on the map
  245. # #######################################################################################
  246. def addRivers():
  247. print "-- addRivers()"
  248. # Generate Marsh-terrain within latitude zones (default: 5, 10, (0,18), (45,63) ).
  249. # The frequency of transformation as well as the zones may be changed by first
  250. # calling mst.marshMaker.initialize() with the appropriate parameters.
  251. mst.marshMaker.initialize( 4, 20, (0,25), (50,75) )
  252. mst.marshMaker.convertTerrain()
  253. # Solidify marsh between 3 [Arid] and 7 [Tropical] percent.
  254. if not mst.bPfall:
  255. if mst.bMarsh:
  256. iAridity = mst.iif( mapOptionAridity==0, 2, 0 ) # Arid
  257. iAridity += mst.iif( mapOptionAridity==2, -2, 0 ) # Wet
  258. marshPer = 5 - iAridity
  259. mst.mapPrettifier.percentifyTerrain( (mst.etMarsh,marshPer), (mst.etTundra,1), (mst.etGrass,2) )
  260. # Expand coastal waters
  261. if mapOptionCoastalWaters == 1:
  262. mst.mapPrettifier.expandifyCoast()
  263. nMaxRegions = 3
  264. if mapOptionLandmass in [4,6,7]: # Islands, Terra, TerraRandom
  265. nMaxRegions = 1
  266. # Build between 0..2 mountain-ranges.
  267. mst.mapRegions.buildBigDents()
  268. # Build between 0..2 bog-regions.
  269. mst.mapRegions.buildBigBogs()
  270. # Generate DeepOcean-terrain if mod allows for it
  271. mst.deepOcean.buildDeepOcean()
  272. # Prettify the map - create better connected deserts and plains
  273. if not mst.bPfall:
  274. mst.mapPrettifier.lumpifyTerrain( mst.etDesert, mst.etPlains, mst.etGrass )
  275. if not mst.bMars:
  276. mst.mapPrettifier.lumpifyTerrain( mst.etPlains, mst.etDesert, mst.etGrass )
  277. # No standard rivers on Mars
  278. if not mst.bMars:
  279. # Tectonics has own river-system
  280. riverGenerator = riversFromSea()
  281. riverGenerator.seedRivers()
  282. # Put rivers on small islands.
  283. mst.riverMaker.islandRivers() # islands between 6 and 50 tiles
  284. # #######################################################################################
  285. # ######## addLakes() - Called from system after addRivers()
  286. # ######## - FOURTH STAGE in 'Generate Map'
  287. # ######## - puts lakes on the map
  288. # #######################################################################################
  289. def addLakes():
  290. print "-- addLakes()"
  291. if not mst.bMars:
  292. CyPythonMgr().allowDefaultImpl()
  293. # #######################################################################################
  294. # ######## addFeatures() - Called from system after addLakes()
  295. # ######## - FIFTH STAGE in 'Generate Map'
  296. # ######## - puts features on the map
  297. # #######################################################################################
  298. def addFeatures():
  299. print "-- addFeatures()"
  300. # Prettify the map - kill off spurious lakes; default: 75% chance
  301. mst.mapPrettifier.connectifyLakes( 90 )
  302. # Sprout rivers from lakes.
  303. mst.riverMaker.buildRiversFromLake( None, 33, 2, 2 ) # all lakes, 33% chance, 2 rivers, lakesize>=2
  304. # select feature generator
  305. if mst.bMars:
  306. featuregen = mst.MST_FeatureGenerator()
  307. else:
  308. if (5 == mapOptionLandmass):
  309. featuregen = MediterraneanFeatureGenerator() # Mediterranean
  310. elif (3 == mapOptionAridity):
  311. featuregen = NoIceFeatureGenerator() # Lakes
  312. else:
  313. featuregen = mst.MST_FeatureGenerator()
  314. # generate features
  315. featuregen.addFeatures()
  316. # Prettify the map - transform coastal volcanos; default: 66% chance
  317. mst.mapPrettifier.beautifyVolcanos()
  318. # Mars Now!: lumpify sandstorms
  319. if mst.bMars: mst.mapPrettifier.lumpifyFeature( mst.efSandStorm, FeatureTypes.NO_FEATURE )
  320. # Planetfall: handle shelves and trenches
  321. if mst.bPfall: mst.planetFallMap.buildPfallOcean()
  322. # FFH: build ElementalQuarter; default: 5% chance
  323. mst.mapRegions.buildElementalQuarter()
  324. # Print featureMap
  325. mst.mapPrint.buildFeatureMap( True, "normalizeAddExtras()" )
  326. # ############################################################################################
  327. # ######## normalizeStartingPlotLocations() - Called from system after starting-plot selection
  328. # ######## - FIRST STAGE in 'Normalize Starting-Plots'
  329. # ######## - change assignments to starting-plots
  330. # ############################################################################################
  331. def normalizeStartingPlotLocations():
  332. print "-- normalizeStartingPlotLocations()"
  333. # build Lost Isle
  334. # - this region needs to be placed after starting-plots are first assigned
  335. mst.mapRegions.buildLostIsle( chance=33, minDist=7, bAliens=mst.choose(33,True,False) )
  336. if mst.bMars:
  337. # Mars Now! uses no teams
  338. CyPythonMgr().allowDefaultImpl()
  339. else:
  340. if mapOptionTeamStart == 0:
  341. CyPythonMgr().allowDefaultImpl() # by default civ places teams near to each other
  342. # mst.teamStart.placeTeamsTogether( True, True ) # use teamStart to place teams near to each other
  343. elif mapOptionTeamStart == 1:
  344. mst.teamStart.placeTeamsTogether( False, True ) # shuffle starting-plots to separate teams
  345. elif mapOptionTeamStart == 2:
  346. mst.teamStart.placeTeamsTogether( True, True ) # randomize starting-plots (may be near or not)
  347. else:
  348. mst.teamStart.placeTeamsTogether( False, False ) # leave starting-plots alone
  349. # ############################################################################################
  350. # ######## normalizeAddRiver() - Called from system after normalizeStartingPlotLocations()
  351. # ######## - SECOND STAGE in 'Normalize Starting-Plots'
  352. # ######## - add some rivers if needed
  353. # ############################################################################################
  354. def normalizeAddRiver():
  355. print "-- normalizeAddRiver()"
  356. if not mst.bMars:
  357. CyPythonMgr().allowDefaultImpl()
  358. # ############################################################################################
  359. # ######## normalizeRemovePeaks() - Called from system after normalizeAddRiver()
  360. # ######## - THIRD STAGE in 'Normalize Starting-Plots'
  361. # ######## - remove some peaks if needed
  362. # ############################################################################################
  363. # A hack. I remove the peaks and I use this as it is the first method called after normalizeAddRiver,
  364. # which needs a post treatment, so it comes here.
  365. def normalizeRemovePeaks():
  366. print "-- normalizeRemovePeaks()"
  367. # Force flood plains
  368. mapWidth = map.getGridWidth()
  369. mapHeight = map.getGridHeight()
  370. width = map.getGridWidth()
  371. height = map.getGridHeight()
  372. for x in range(width):
  373. for y in range(height):
  374. addFloodPlains(map.plot(x,y))
  375. # And now the peaks.
  376. ########## Temudjin Start
  377. if mst.bPfall: return
  378. ########## Temudjin End
  379. CyPythonMgr().allowDefaultImpl()
  380. # ############################################################################################
  381. # ######## normalizeAddLakesRiver() - Called from system after normalizeRemovePeaks()
  382. # ######## - FOURTH STAGE in 'Normalize Starting-Plots'
  383. # ######## - add some lakes if needed
  384. # ############################################################################################
  385. def normalizeAddLakes():
  386. print "-- normalizeAddLakes()"
  387. if not mst.bMars:
  388. CyPythonMgr().allowDefaultImpl()
  389. # ############################################################################################
  390. # ######## normalizeRemoveBadFeatures() - Called from system after normalizeAddLakes()
  391. # ######## - FIFTH STAGE in 'Normalize Starting-Plots'
  392. # ######## - remove bad features if needed
  393. # ############################################################################################
  394. def normalizeRemoveBadFeatures():
  395. print "-- normalizeRemoveBadFeatures()"
  396. return None
  397. # ############################################################################################
  398. # ######## normalizeRemoveBadTerrain() - Called from system after normalizeRemoveBadFeatures()
  399. # ######## - SIXTH STAGE in 'Normalize Starting-Plots'
  400. # ######## - change bad terrain if needed
  401. # ############################################################################################
  402. def normalizeRemoveBadTerrain():
  403. print "-- normalizeRemoveBadTerrain()"
  404. if not (mst.bPfall or mst.bMars):
  405. CyPythonMgr().allowDefaultImpl()
  406. # ############################################################################################
  407. # ######## normalizeAddFoodBonuses() - Called from system after normalizeRemoveBadTerrain()
  408. # ######## - SEVENTH STAGE in 'Normalize Starting-Plots'
  409. # ######## - add food if needed
  410. # ############################################################################################
  411. def normalizeAddFoodBonuses():
  412. print "-- normalizeAddFoodBonuses()"
  413. if mst.bMars:
  414. CyPythonMgr().allowDefaultImpl()
  415. # ############################################################################################
  416. # ######## normalizeAddGoodTerrain() - Called from system after normalizeAddFoodBonuses()
  417. # ######## - EIGHTH STAGE in 'Normalize Starting-Plots'
  418. # ######## - add good terrain if needed
  419. # ############################################################################################
  420. def normalizeAddGoodTerrain():
  421. print "-- normalizeAddGoodTerrain()"
  422. if not (mst.bPfall or mst.bMars):
  423. CyPythonMgr().allowDefaultImpl()
  424. # This function will be called by the system, after the map was generated, after the
  425. # starting-plots have been choosen, at the end of the normalizing process and
  426. # before startHumansOnSameTile() which is the last map-function so called.
  427. # - balance boni (depending on initialization also place missing boni and move minerals)
  428. # - give names and boni to special regions
  429. # - print plot-map and the difference-map to the call before
  430. # - print other maps
  431. # - print river-map with plots, rivers and starting-plots
  432. # - print map and mod statistics
  433. # --------------------------------------------------------------------------------------
  434. def normalizeAddExtras():
  435. print "-- normalizeAddExtras()"
  436. # Balance boni, place missing boni and move minerals depending on initialization.
  437. if mapOptionLandmass == 3: # lakes map option
  438. mst.bonusBalancer.normalizeAddExtras( '-BONUS_WHALE' )
  439. else:
  440. mst.bonusBalancer.normalizeAddExtras()
  441. # Do the default housekeeping
  442. CyPythonMgr().allowDefaultImpl()
  443. # Make sure marshes are on flatlands
  444. mst.marshMaker.normalizeMarshes()
  445. # Give extras to special regions
  446. mst.mapRegions.addRegionExtras()
  447. # Place special features on map
  448. mst.featurePlacer.placeFeatures()
  449. # Kill ice on warm edges
  450. mst.mapPrettifier.deIcifyEdges()
  451. # Print plotMap and differencePlotMap
  452. mst.mapPrint.buildPlotMap( True, "normalizeAddExtras()" )
  453. # Print areaMap
  454. mst.mapPrint.buildAreaMap( True, "normalizeAddExtras()" )
  455. # Print terrainMap
  456. mst.mapPrint.buildTerrainMap( True, "normalizeAddExtras()" )
  457. # Print featureMap
  458. mst.mapPrint.buildFeatureMap( True, "normalizeAddExtras()" )
  459. # Print bonusMap
  460. mst.mapPrint.buildBonusMap( True, "normalizeAddExtras()" )
  461. # Print manaMap if FFH
  462. if mst.bFFH: mst.mapPrint.buildBonusMap( True, "normalizeAddExtras():Mana", None, mst.mapPrint.manaDict )
  463. # Print riverMap
  464. mst.mapPrint.buildRiverMap( True, "normalizeAddExtras()" )
  465. # Print mod and map statistics
  466. mst.mapStats.mapStatistics()
  467. # This function will be called at odd times by the system.
  468. # 'Planetfall' wants nearer starting-plots
  469. # If the script already has this function, return that result instead of zero or rename it.
  470. def minStartingDistanceModifier():
  471. if mst.bPfall: return -25
  472. if mst.bMars: return -15
  473. return 0
  474. ################################################################
  475. ## Custom Map Option Interface by Temudjin START
  476. ################################################################
  477. def setCustomOptions():
  478. """ Set all custom options in one place """
  479. global op # { optionID: Name, OptionList, Default, RandomOpt }
  480. # Initialize options to the default values.
  481. lMapOptions = [0, 0, 1, 0, 0]
  482. # Try to read map options from the cfgFile.
  483. mst.mapOptionsStorage.initialize(lMapOptions, 'Tectonics')
  484. lMapOptions = mst.mapOptionsStorage.readConfig()
  485. optionLandmass = [ "TXT_KEY_MAP_SCRIPT_EARTH_70", "TXT_KEY_MAP_SCRIPT_EARTH_60",
  486. "TXT_KEY_MAP_SCRIPT_PANGAEA", "TXT_KEY_MAP_SCRIPT_LAKES",
  487. "TXT_KEY_MAP_SCRIPT_ISLANDS", "TXT_KEY_MAP_SCRIPT_MEDITERRANEAN",
  488. "TXT_KEY_MAP_SCRIPT_TERRA", "TXT_KEY_MAP_SCRIPT_TERRA_OLD_WORLD_START" ]
  489. optionAridity = [ "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_ARID", "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_NORMAL",
  490. "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_WET", "TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY_NO_ICE" ]
  491. op = {
  492. 0: ["TXT_KEY_MAP_RESOURCES", ["TXT_KEY_MAP_RESOURCES_STANDARD", "TXT_KEY_MAP_RESOURCES_BALANCED"], lMapOptions[0], True],
  493. 1: ["TXT_KEY_MAP_SCRIPT_LANDMASS_TYPE", optionLandmass, lMapOptions[1], True],
  494. 2: ["TXT_KEY_MAP_SCRIPT_TECTONICS_ARITITY", optionAridity, lMapOptions[2], True],
  495. 3: ["TXT_KEY_MAP_COASTS", ["TXT_KEY_MAP_COASTS_STANDARD", "TXT_KEY_MAP_COASTS_EXPANDED"], lMapOptions[3], True],
  496. 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],
  497. "Hidden": mst.iif( mst.bPfall, 3, 2 )
  498. }
  499. if mst.bMars:
  500. 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]
  501. elif mst.bPfall:
  502. 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]
  503. mst.printDict(op,"Tectonics Map Options:")
  504. def isAdvancedMap():
  505. """ This map should show up in simple mode """
  506. return 0
  507. # first function to be called by the map building process
  508. def getNumHiddenCustomMapOptions():
  509. """ Default is used for the last n custom-options in 'Play Now' mode. """
  510. setCustomOptions() # Define Options
  511. return op["Hidden"]
  512. def getNumCustomMapOptions():
  513. """ Number of different user-defined options for this map """
  514. return len( op ) - 1
  515. def getCustomMapOptionName(argsList):
  516. """ Returns name of specified option """
  517. optionID = argsList[0]
  518. translated_text = unicode(CyTranslator().getText(op[optionID][0], ()))
  519. return translated_text
  520. def getNumCustomMapOptionValues(argsList):
  521. """ Number of different choices for a particular setting """
  522. optionID = argsList[0]
  523. return len( op[optionID][1] )
  524. def getCustomMapOptionDescAt(argsList):
  525. """ Returns name of value of option at specified row """
  526. optionID = argsList[0]
  527. valueID = argsList[1]
  528. translated_text = unicode(CyTranslator().getText(op[optionID][1][valueID], ()))
  529. return translated_text
  530. def getCustomMapOptionDefault(argsList):
  531. """ Returns default value of specified option """
  532. optionID = argsList[0]
  533. return op[optionID][2]
  534. def isRandomCustomMapOption(argsList):
  535. """ Returns a flag indicating whether a random option should be provided """
  536. optionID = argsList[0]
  537. return op[optionID][3]
  538. ################################################################
  539. ## Interfaces by Temudjin END
  540. ################################################################
  541. def isClimateMap():
  542. """ Does not use the Climate options """
  543. return False
  544. def isSeaLevelMap():
  545. """ Does not use the Sea Level options """
  546. return False
  547. def getTopLatitude():
  548. """ Default is 90. 75 is past the Arctic Circle """
  549. if (5 == mapOptionLandmass): return 65
  550. return 90
  551. def getBottomLatitude():
  552. """ Default is -90. -75 is past the Antartic Circle """
  553. if (5 == mapOptionLandmass): return 25
  554. return -90
  555. def getWrapX():
  556. if (5 == mapOptionLandmass): return False
  557. return True
  558. def getWrapY():
  559. return False
  560. ##########
  561. class voronoiMap:
  562. def __init__(self,landPlates,seaPlates,hotspotsF):
  563. self.dice = gc.getGame().getMapRand()
  564. self.mapWidth = map.getGridWidth()
  565. self.mapHeight = map.getGridHeight()
  566. self.plotTypes = [PlotTypes.PLOT_OCEAN] * (self.mapWidth*self.mapHeight)
  567. self.heightMap = [0] * (self.mapWidth*self.mapHeight)
  568. self.plateMap = [0] * (self.mapWidth*self.mapHeight)
  569. self.numContinents = landPlates
  570. self.hotSpotFrequency = hotspotsF
  571. self.numSeaPlates = seaPlates + 1 # plate 0 is for initialisation
  572. self.plate = [0] * (self.numContinents + self.numSeaPlates)
  573. # plateSize is a random number which gives the probability of growing a plate
  574. self.plateSize = [0] * (self.numContinents + self.numSeaPlates)
  575. self.altitudeVariation = 2
  576. self.peakAltitude = 12 ########## Temudjin was 12
  577. self.hillAltitude = 9 ########## Temudjin was 9
  578. self.landAltitude = 6 ########## Temudjin was 6
  579. for x in range(self.mapWidth):
  580. for y in range(self.mapHeight):
  581. i = y*self.mapWidth + x
  582. self.plotTypes[i] = PlotTypes.PLOT_OCEAN
  583. def generate(self):
  584. self.sowSeeds()
  585. self.fillPlates()
  586. self.movePlates(true)
  587. self.erode()
  588. self.movePlates(false)
  589. self.blur()
  590. self.addFaults()
  591. self.hotspots()
  592. self.createMap()
  593. self.finalizeMap()
  594. return self.plotTypes
  595. def sowSeeds(self):
  596. self.mostLands = self.dice.get(2,"mostland hemisphere")
  597. for i in range(self.numSeaPlates):
  598. self.plate[i] = self.dice.get(3,"Sea altitude")
  599. for i in range(self.numContinents):
  600. self.plate[self.numSeaPlates + i] = self.landAltitude + self.dice.get(3,"Land altitude")
  601. for i in range(self.numContinents + self.numSeaPlates):
  602. x, y = self.getCoord(i)
  603. while self.plateMap[y*self.mapWidth + x] != 0:
  604. x, y = self.getCoord(i)
  605. self.plateMap[y*self.mapWidth + x] = i
  606. self.plateSize[i] = 3 + self.dice.get(6,"Some randomness in plate sizes") ########## Temidjin was 2
  607. def getCoord(self,i):
  608. x = self.dice.get(self.mapWidth,"x seed for plate")
  609. if (i >= self.numSeaPlates + (self.numContinents/3)):
  610. y = 2 + self.dice.get(2*self.mapHeight/3,"y seed for plate")
  611. if (i >= self.numSeaPlates + 1 + (self.numContinents/3)):
  612. if (self.mostLands == 0):
  613. y = self.mapHeight - y - 1
  614. elif (self.mostLands == 1):
  615. y = self.mapHeight - y - 1
  616. else:
  617. y = self.dice.get(self.mapHeight,"y seed for plate")
  618. return x, y
  619. def fillPlates(self):
  620. filled = False
  621. bufferPlateMap = [0] * (self.mapWidth*self.mapHeight)
  622. while filled == False:
  623. filled = True
  624. for x in range(self.mapWidth):
  625. for y in range(self.mapHeight):
  626. i = y*self.mapWidth + x
  627. bufferPlateMap[i] = self.plateMap[i]
  628. if (self.plateMap[i] == 0):
  629. bufferPlateMap[i] = self.neighbour(x,y)
  630. for x in range(self.mapWidth):
  631. for y in range(self.mapHeight):
  632. i = y*self.mapWidth + x
  633. self.plateMap[i] = bufferPlateMap[i]
  634. if self.plateMap[i] == 0:
  635. filled = False
  636. for x in range(self.mapWidth):
  637. for y in range(self.mapHeight):
  638. i = y*self.mapWidth + x
  639. self.heightMap[i] = self.plate[self.plateMap[i]] + self.dice.get(self.altitudeVariation,"Random variation of altitude")
  640. def movePlates(self,dontMoveSeaPlates):
  641. plates = self.numContinents + self.numSeaPlates
  642. xMoves = [0] * plates
  643. yMoves = [0] * plates
  644. subduction = [0] * plates
  645. min = 0
  646. if dontMoveSeaPlates:
  647. min = self.numSeaPlates
  648. for i in range(min,plates):
  649. xMoves[i] = self.dice.get(3,"moves") - 2
  650. yMoves[i] = self.dice.get(3,"moves") - 2
  651. subduction[i] = self.dice.get(10,"subduction")
  652. self.doMovePlates(xMoves,yMoves,subduction)
  653. def doMovePlates(self,xMoves,yMoves,subduction):
  654. mapSize = self.mapWidth*self.mapHeight
  655. #FIXME There must be a clone method somewhere?
  656. oldHeightMap = [0] * mapSize
  657. for i in range(mapSize):
  658. oldHeightMap[i] = self.heightMap[i]
  659. for x in range(self.mapWidth):
  660. for y in range(self.mapHeight):
  661. currentCoord = y*self.mapWidth + x
  662. currentPlate = self.plateMap[currentCoord]
  663. if (xMoves[currentPlate] != 0 or yMoves[currentPlate] != 0):
  664. movedX = x + xMoves[currentPlate]
  665. movedY = y + yMoves[currentPlate]
  666. if (movedX >= 0 and movedX < self.mapWidth):
  667. if (movedY >= 0 and movedY < self.mapHeight):
  668. movedCoord = movedY*self.mapWidth + movedX
  669. targetPlate = self.plateMap[movedCoord]
  670. if (targetPlate != currentPlate):
  671. if (subduction[currentPlate] >= 6):
  672. sum = oldHeightMap[movedCoord] + oldHeightMap[currentCoord] + 2
  673. if (self.heightMap[movedCoord] < sum ):
  674. self.heightMap[movedCoord] = sum
  675. self.heightMap[currentCoord] = self.heightMap[currentCoord] -1
  676. else:
  677. sum = oldHeightMap[movedCoord] + oldHeightMap[currentCoord] -2
  678. if (self.heightMap[movedCoord] < sum and self.heightMap[movedCoord] >= self.landAltitude):
  679. self.heightMap[movedCoord] = sum
  680. if (self.heightMap[currentCoord] < sum and self.heightMap[currentCoord] >= self.landAltitude):
  681. self.heightMap[currentCoord] = sum
  682. def addFaults(self):
  683. "Adds faultlines to break up big flat land masses. Think Rift Valley."
  684. plates = self.numContinents + self.numSeaPlates
  685. width = [0] * plates
  686. height = [0] * plates
  687. sum = [0] * plates
  688. lastPlate = 0
  689. for x in range(self.mapWidth):
  690. for y in range(self.mapHeight):
  691. currentCoord = y*self.mapWidth + x
  692. lastPlate = self.checkFault(currentCoord,sum,height,lastPlate)
  693. for y in range(self.mapHeight):
  694. for x in range(self.mapWidth):
  695. currentCoord = y*self.mapWidth + x
  696. lastPlate = self.checkFault(currentCoord,sum,width,lastPlate)
  697. for i in range(plates):
  698. if (width[i] != 0): self.verticalFault(i,width[i])
  699. elif (height[i] != 0): self.horizontalFault(i,height[i])
  700. def checkFault(self,currentCoord,sum,table,lastPlate):
  701. plates = self.numContinents + self.numSeaPlates
  702. faultLimit = 7
  703. if (self.heightMap[currentCoord] <= self.landAltitude):
  704. return 0
  705. if (self.heightMap[currentCoord] > self.hillAltitude):
  706. return 0
  707. currentPlate = self.plateMap[currentCoord]
  708. if (lastPlate != currentPlate):
  709. if (sum[lastPlate] >= 0):
  710. sum[lastPlate] = 0
  711. lastPlate = currentPlate
  712. elif (sum[lastPlate] >= 0):
  713. sum[lastPlate] = 1 + sum[lastPlate]
  714. if (sum[lastPlate] > faultLimit):
  715. table[lastPlate] = currentCoord
  716. sum[lastPlate] = -1
  717. return lastPlate
  718. def verticalFault(self,plateNumber,coord):
  719. nextCoord = coord - 3 + self.dice.get(6,"Fault position")
  720. mapSize = self.mapWidth*self.mapHeight
  721. while (nextCoord >= 0 and nextCoord < mapSize):
  722. if (self.plateMap[nextCoord] != plateNumber):
  723. break
  724. self.fault(nextCoord)
  725. nextCoord = nextCoord + self.mapWidth + self.dice.get(3,"Fault tilt") - 1
  726. def horizontalFault(self,plateNumber,coord):
  727. nextCoord = coord + (self.dice.get(6,"Fault position") - 3) * self.mapWidth
  728. mapSize = self.mapWidth*self.mapHeight
  729. max = coord + self.mapWidth
  730. if (max > mapSize):
  731. max = mapSize
  732. while (nextCoord >= 0 and nextCoord < max):
  733. if (self.plateMap[nextCoord] != plateNumber):
  734. break
  735. self.fault(nextCoord)
  736. nextCoord = nextCoord + 1 + (self.dice.get(3,"Fault tilt") - 1)*self.mapWidth
  737. def fault(self,coord):
  738. dieRoll = self.dice.get(20,"Fault line effect")
  739. if (dieRoll > 11):
  740. self.heightMap[coord] = self.hillAltitude + 1
  741. elif (dieRoll > 9):
  742. self.heightMap[coord] = 0
  743. def erode(self):
  744. for x in range(self.mapWidth):
  745. for y in range(self.mapHeight):
  746. i = y*self.mapWidth + x
  747. if self.heightMap[i] > self.peakAltitude:
  748. self.heightMap[i] -= 2
  749. if self.heightMap[i] > self.hillAltitude:
  750. self.heightMap[i] -= 1
  751. hasSeaNeighbour = False
  752. hasHillNeighbour = False
  753. leftX = x-1
  754. if (leftX < 0):
  755. leftX = self.mapWidth - 1
  756. left = self.heightMap[leftX + y*self.mapWidth]
  757. if (left < self.landAltitude):
  758. hasSeaNeighbour = True
  759. elif (left > self.hillAltitude):
  760. hasHillNeighbour = True
  761. rightX = x+1
  762. if (rightX >= self.mapWidth):
  763. rightX = 0
  764. right = self.heightMap[rightX + y*self.mapWidth]
  765. if (right < self.landAltitude):
  766. hasSeaNeighbour = True
  767. elif (right > self.hillAltitude):
  768. hasHillNeighbour = True
  769. if (y>0):
  770. top = self.heightMap[x + (y-1)*self.mapWidth]
  771. if (top < self.landAltitude):
  772. hasSeaNeighbour = True
  773. elif (top > self.hillAltitude):
  774. hasHillNeighbour = True
  775. if (y<self.mapHeight - 2):
  776. bottom = self.heightMap[x + (y+1)*self.mapWidth]
  777. if (bottom < self.landAltitude):
  778. hasSeaNeighbour = True
  779. elif (bottom > self.hillAltitude):
  780. hasHillNeighbour = True
  781. if (hasSeaNeighbour):
  782. self.heightMap[i] = self.heightMap[i] - 1
  783. if (hasHillNeighbour):
  784. self.heightMap[i] = self.heightMap[i] - 1
  785. def min( height, left, right, top, bottom ):
  786. minHeight = height
  787. if ( minHeight > left ):
  788. minHeight = left
  789. if ( minHeight > right ):
  790. minHeight = right
  791. if ( minHeight > top ):
  792. minHeight = top
  793. if ( minHeight > bottom ):
  794. minHeight = bottom
  795. return minHeight
  796. def blur(self):
  797. #FIXME There must be a clone method somewhere?
  798. mapSize = self.mapWidth*self.mapHeight
  799. oldHeightMap = [0] * (mapSize)
  800. for i in range(mapSize):
  801. oldHeightMap[i] = self.heightMap[i]
  802. for x in range(self.mapWidth):
  803. for y in range(self.mapHeight):
  804. i = y*self.mapWidth + x
  805. height = self.heightMap[i]
  806. leftX = x-1
  807. if (leftX < 0):
  808. leftX = self.mapWidth - 1
  809. left = oldHeightMap[leftX + y*self.mapWidth]
  810. rightX = x+1
  811. if (rightX >= self.mapWidth):
  812. rightX = 0
  813. right = oldHeightMap[rightX + y*self.mapWidth]
  814. top = height
  815. if (y>0):
  816. top = oldHeightMap[x + (y-1)*self.mapWidth]
  817. bottom = height
  818. if (y<self.mapHeight - 2):
  819. bottom = oldHeightMap[x + (y+1)*self.mapWidth]
  820. self.heightMap[i] = (height * 4 + left + right + top + bottom) / 8
  821. minHeight = min(height,left,right,top,bottom)
  822. if (minHeight >= self.peakAltitude):
  823. oldHeightMap[leftX + y*self.mapWidth] = self.hillAltitude + 1
  824. self.heightMap[leftX + y*self.mapWidth] = self.hillAltitude + 1
  825. oldHeightMap[rightX + y*self.mapWidth] = self.hillAltitude + 1
  826. self.heightMap[rightX + y*self.mapWidth] = self.hillAltitude + 1
  827. if (y>0):
  828. oldHeightMap[x + (y-1)*self.mapWidth] = self.hillAltitude + 1
  829. self.heightMap[x + (y-1)*self.mapWidth] = self.hillAltitude + 1
  830. if (y<self.mapHeight - 2):
  831. oldHeightMap[x + (y+1)*self.mapWidth] = self.hillAltitude + 1
  832. self.heightMap[x + (y+1)*self.mapWidth] = self.hillAltitude + 1
  833. def hotspots(self):
  834. mapSize = self.mapWidth * self.mapHeight
  835. hotSpotsNumber = mapSize/self.hotSpotFrequency
  836. for hotspot in range(hotSpotsNumber):
  837. i = self.dice.get(mapSize,"Hotspot location")
  838. self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")
  839. def createMap(self):
  840. for y in range(self.mapHeight):
  841. for x in range(self.mapWidth):
  842. i = y*self.mapWidth + x
  843. height = self.heightMap[i]
  844. if (height > self.peakAltitude):
  845. if (self.dice.get(7,"Random pass") == 6):
  846. self.plotTypes[i] = PlotTypes.PLOT_HILLS
  847. else:
  848. self.plotTypes[i] = PlotTypes.PLOT_PEAK
  849. elif (height > self.hillAltitude):
  850. if (self.dice.get(20,"Random peak") == 19):
  851. self.plotTypes[i] = PlotTypes.PLOT_PEAK
  852. else:
  853. self.plotTypes[i] = PlotTypes.PLOT_HILLS
  854. elif (height > self.landAltitude):
  855. self.plotTypes[i] = PlotTypes.PLOT_LAND
  856. else:
  857. self.plotTypes[i] = PlotTypes.PLOT_OCEAN
  858. def finalizeMap(self):
  859. return
  860. def neighbour(self,x,y):
  861. roll = self.dice.get(10,"Some randomness in plate shapes")
  862. leftX = x-1
  863. if (leftX < 0):
  864. leftX = self.mapWidth - 1
  865. left = self.plateMap[leftX + y*self.mapWidth]
  866. if (left != 0):
  867. if (roll <= self.plateSize[left]):
  868. return left
  869. rightX = x+1
  870. if (rightX >= self.mapWidth):
  871. rightX = 0
  872. right = self.plateMap[rightX + y*self.mapWidth]
  873. if (right != 0):
  874. if (roll <= self.plateSize[right]):
  875. return right
  876. if (y>0):
  877. top = self.plateMap[x + (y-1)*self.mapWidth]
  878. if (top != 0):
  879. if (roll <= self.plateSize[top]):
  880. return top
  881. if (y<self.mapHeight - 2):
  882. bottom = self.plateMap[x + (y+1)*self.mapWidth]
  883. if (bottom != 0):
  884. if (roll <= self.plateSize[bottom]):
  885. return bottom
  886. return 0
  887. class voronoiMediterraneanMap(voronoiMap):
  888. def __init__(self,numPlayers):
  889. voronoiMap.__init__(self,numPlayers*5/2, numPlayers,150)
  890. self.peakAltitude = 13
  891. def movePlates(self,dontMoveSeaPlates):
  892. if dontMoveSeaPlates:
  893. return
  894. voronoiMap.movePlates(self,true)
  895. def getCoord(self,i):
  896. mapWidthFraction = self.mapWidth/self.numSeaPlates
  897. # Sea plates
  898. if (i < self.numSeaPlates):
  899. x = mapWidthFraction*i + self.dice.get(mapWidthFraction,"x seed for sea plate")
  900. y = self.mapHeight/3 + self.dice.get(self.mapHeight/3,"y seed for plate")
  901. else:
  902. # One land plate to the east to link north and south
  903. if (i == self.numSeaPlates + self.numContinents - 1):
  904. x = self.dice.get(self.mapWidth - 2,"x seed for link land plate")
  905. y = self.mapHeight/3 + self.dice.get(self.mapHeight/3,"y seed for land plate")
  906. # Other land plates half north half south
  907. elif (i < self.numSeaPlates * 2):
  908. x = mapWidthFraction * (i - self.numSeaPlates) + self.dice.get(mapWidthFraction,"x seed for land plate")
  909. y = self.getLandY(0)
  910. elif (i >= self.numSeaPlates * 3):
  911. x = mapWidthFraction * (i - 2*self.numSeaPlates) + self.dice.get(mapWidthFraction,"x seed for land plate")
  912. y = self.getLandY(1)
  913. else:
  914. x = self.dice.get(self.mapWidth,"x seed for land plate")
  915. y = self.getLandY(i)
  916. return x, y
  917. def getLandY(self,i):
  918. y = 1 + self.dice.get(self.mapHeight/4,"y seed for land plate")
  919. if (i == 2*(i/2)):
  920. y = y + self.mapHeight*3/4 -1
  921. return y
  922. def hotspots(self):
  923. mapSize = self.mapWidth * self.mapHeight
  924. hotSpotsNumber = mapSize/self.hotSpotFrequency
  925. minX = 2
  926. maxX = self.mapWidth*9/10
  927. minY = self.mapHeight/10
  928. yRange = self.mapHeight*8/10
  929. for hotspot in range(hotSpotsNumber):
  930. x = minX + self.dice.get(maxX,"Hotspot X")
  931. y = minY + self.dice.get(yRange,"Hotspot Y")
  932. i = y*self.mapWidth + x
  933. while (self.plotTypes[i] != PlotTypes.PLOT_OCEAN):
  934. x = minX + self.dice.get(maxX,"Hotspot X")
  935. y = minY + self.dice.get(yRange,"Hotspot Y")
  936. i = y*self.mapWidth + x
  937. self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")
  938. self.spreadHotSpot(i)
  939. def spreadHotSpot(self,i):
  940. self.spreadIsland(i+1)
  941. self.spreadIsland(i-1)
  942. self.spreadIsland(i+self.mapWidth)
  943. self.spreadIsland(i-self.mapWidth)
  944. def spreadIsland(self,i):
  945. self.heightMap[i] = self.heightMap[i] + self.dice.get(self.peakAltitude,"Hotspot altitude")
  946. if (self.heightMap[i] > self.landAltitude):
  947. self.spreadBigIsland(i+1)
  948. self.spreadBigIsland(i-1)
  949. self.spreadBigIsland(i+self.mapWidth)
  950. self.spreadBigIsland(i-self.mapWidth)
  951. def spreadBigIsland(self,i):
  952. if (self.heightMap[i] <= self.landAltitude):
  953. self.heightMap[i] = self.dice.get(self.peakAltitude,"Island altitude")
  954. def finalizeMap(self):
  955. # Make sure that the north and south borders are made of land.
  956. for y in range(self.mapHeight):
  957. for x in range(self.mapWidth):
  958. if self.checkY(y):
  959. i = y*self.mapWidth + x
  960. if (self.plotTypes[i] == PlotTypes.PLOT_OCEAN):
  961. self.plotTypes[i] = PlotTypes.PLOT_LAND
  962. # Make sure that there's a way north/south by foot or galley
  963. minEastWidth = self.mapWidth * 9 /10
  964. margin = self.mapWidth/10
  965. for y in range(self.mapHeight-1):
  966. for x in range(minEastWidth,self.mapWidth):
  967. if (x + 3 + self.dice.get(margin,"Border")) > self.mapWidth:
  968. i = y*self.mapWidth + x
  969. if (self.plotTypes[i] == PlotTypes.PLOT_OCEAN):
  970. self.plotTypes[i] = PlotTypes.PLOT_LAND
  971. def checkY(self,y):
  972. if (y > 9*self.mapHeight/10):
  973. y = self.mapHeight - y
  974. if (y < self.mapHeight/10):
  975. if (2 + self.dice.get(self.mapHeight/10,"Border")) > y:
  976. return True
  977. return False
  978. class voronoiTerraMap(voronoiMap):
  979. def __init__(self):
  980. voronoiMap.__init__(self,12,8,800)
  981. self.altitudeVariation = 3
  982. def sowSeeds(self):
  983. for i in range(0,8):
  984. self.plate[i] = 2
  985. for i in range(8,20):
  986. self.plate[i] = self.landAltitude + 3
  987. #Pacific Ocean
  988. for i in range(self.mapHeight):
  989. self.plateMap[i*self.mapWidth] = 1
  990. for i in range(self.mapWidth/10):
  991. self.plateMap[self.mapHeight*self.mapWidth/2 -self.mapWidth/20 + i] = 1
  992. x = self.mapWidth/10
  993. y = self.mapHeight/5
  994. self.plateMap[x + y*self.mapWidth] = 1
  995. self.plateSize[1] = 7
  996. #North Atlantic
  997. x = self.mapWidth/3
  998. ymin = 2*self.mapHeight/3
  999. ymax = 7*self.mapHeight/8
  1000. for y in range(ymin,ymax):
  1001. self.plateMap[x + y*self.mapWidth] = 2
  1002. x = 3*self.mapWidth/10
  1003. y = 3*self.mapHeight/5
  1004. self.plateMap[x + y*self.mapWidth] = 2
  1005. self.plateSize[2] = 7
  1006. #South Atlantic
  1007. x = self.mapWidth/3
  1008. yMin = self.mapHeight/5
  1009. yMax = self.mapHeight/3
  1010. for y in range(yMin,yMax):
  1011. self.plateMap[x + y*self.mapWidth] = 3
  1012. for x in range(self.mapWidth/4,self.mapWidth/2):
  1013. self.plateMap[self.mapWidth/3 + self.mapHeight/5*self.mapWidth] = 3
  1014. x = self.mapWidth/3
  1015. y= 5*self.mapHeight/12
  1016. self.plateMap[x + y*self.mapWidth] = 3
  1017. x = self.mapWidth/4 +1
  1018. y = self.mapHeight/4
  1019. self.plateMap[x + y*self.mapWidth] = 3
  1020. self.plateSize[3] = 7
  1021. #Arctic Ocean
  1022. for i in range(self.mapWidth):
  1023. self.plateMap[self.mapWidth*(self.mapHeight-2) + i] = 4
  1024. self.plateSize[4] = 3
  1025. #Mediterranean
  1026. x = 4*self.mapWidth/9
  1027. y = 3*self.mapHeight/4
  1028. self.plateMap[x + y*self.mapWidth] = 5
  1029. self.plateSize[5] = 4
  1030. #Indian Ocean
  1031. x = 3*self.mapWidth/4
  1032. y = self.mapHeight/3
  1033. self.plateMap[x + y*self.mapWidth] = 6
  1034. x = 3*self.mapWidth/5
  1035. y = self.mapHeight/3
  1036. self.plateMap[x + y*self.mapWidth] = 6
  1037. x = 2*self.mapWidth/3
  1038. y = 9*self.mapHeight/20
  1039. self.plateMap[x + y*self.mapWidth] = 6
  1040. self.plateSize[6] = 7
  1041. #Antarctic Ocean
  1042. y = self.mapHeight/8
  1043. for i in range(self.mapWidth):
  1044. self.plateMap[i+y*self.mapWidth] = 7
  1045. self.plateSize[7] = 4
  1046. #North America
  1047. x = self.mapWidth/5
  1048. yMin = 4*self.mapHeight/5
  1049. yMax = 6*self.mapHeight/7
  1050. for y in range(yMin,yMax):
  1051. self.plateMap[x + y*self.mapWidth] = 8
  1052. self.plateMap[self.mapWidth/20 + yMax*self.mapWidth] = 8
  1053. self.plateSize[8] = 8
  1054. #South America
  1055. x = self.mapWidth/5
  1056. y = self.mapHeight/4
  1057. self.plateMap[x + y*self.mapWidth] = 9
  1058. y = self.mapHeight/3
  1059. self.plateMap[x + y*self.mapWidth] = 9
  1060. x = self.mapWidth/4 +1
  1061. y = 2*self.mapHeight/5
  1062. self.plateMap[x + y*self.mapWidth] = 9
  1063. self.plateSize[9] = 5
  1064. #Europe
  1065. x = self.mapWidth/2
  1066. y = 6*self.mapHeight/7
  1067. self.plateMap[x + y*self.mapWidth] = 10
  1068. x = 3*self.mapWidth/7
  1069. y = 4*self.mapHeight/5
  1070. self.plateMap[x + y*self.mapWidth] = 10
  1071. self.plateSize[10] = 6
  1072. #Asia
  1073. x = 3*self.mapWidth/4
  1074. y = 7*self.mapHeight/10
  1075. self.plateMap[x + y*self.mapWidth] = 11
  1076. x = 4*self.mapWidth/5
  1077. y = 4*self.mapHeight/5
  1078. self.plateMap[x + y*self.mapWidth] = 11
  1079. x = 2*self.mapWidth/3
  1080. y = 4*self.mapHeight/5
  1081. self.plateMap[x + y*self.mapWidth] = 11
  1082. self.plateSize[11] = 9
  1083. #Africa
  1084. x = 7*self.mapWidth/20
  1085. y = 2*self.mapHeight/3 -1
  1086. for i in range(self.mapWidth/12):
  1087. self.plateMap[x + i + y*self.mapWidth] = 12
  1088. x = self.mapWidth/2
  1089. y = 2*self.mapHeight/5
  1090. self.plateMap[x + y*self.mapWidth] = 12
  1091. self.plateSize[12] = 6
  1092. #India
  1093. x = 3*self.mapWidth/4
  1094. y = 5*self.mapHeight/9
  1095. self.plateMap[x + y*self.mapWidth] = 13
  1096. self.plateSize[13] = 3
  1097. #Oceania
  1098. x = 4*self.mapWidth/5
  1099. y = self.mapHeight/4 +1
  1100. self.plateMap[x + y*self.mapWidth] = 14
  1101. self.plateSize[14] = 4
  1102. #Middle East
  1103. x = 3*self.mapWidth/5
  1104. y = 4*self.mapHeight/7
  1105. self.plateMap[x + y*self.mapWidth] = 15
  1106. self.plateSize[15] = 2
  1107. self.plate[15] = self.landAltitude + 1
  1108. #South East Asia
  1109. x = 17*self.mapWidth/20
  1110. y = 4*self.mapHeight/7
  1111. self.plateMap[x + y*self.mapWidth] = 16
  1112. self.plateSize[16] = 3
  1113. self.plate[16] = self.landAltitude
  1114. #Greenland
  1115. x = 3*self.mapWidth/10
  1116. y = 7*self.mapHeight/8
  1117. self.plateMap[x + y*self.mapWidth] = 17
  1118. self.plateSize[17] = 4
  1119. #Scandinavia
  1120. x = 3*self.mapWidth/7 -1
  1121. y = 7*self.mapHeight/8
  1122. self.plateMap[x + y*self.mapWidth] = 18
  1123. self.plateSize[18] = 3
  1124. self.plate[18] = self.landAltitude
  1125. #Bering
  1126. x = 9*self.mapWidth/10
  1127. y = 5*self.mapHeight/6
  1128. self.plateMap[x + y*self.mapWidth] = 19
  1129. self.plateSize[19] = 5
  1130. def finalizeMap(self):
  1131. #Force Gibraltar straits
  1132. x = 4*self.mapWidth/9
  1133. y = 3*self.mapHeight/4
  1134. for i in range(self.mapWidth/5):
  1135. self.plotTypes[x + y*self.mapWidth - i] = PlotTypes.PLOT_OCEAN
  1136. #Force cut between India and Oceania
  1137. x = 7*self.mapWidth/10
  1138. y = 4*self.mapHeight/9 -1
  1139. for i in range(self.mapWidth/5):
  1140. self.plotTypes[x + y*self.mapWidth + i] = PlotTypes.PLOT_OCEAN
  1141. #Force Greenland to be an island
  1142. for x in range(self.mapWidth):
  1143. for y in range(self.mapHeight):
  1144. if (self.plateMap[x + y*self.mapWidth] == 17):
  1145. if (self.plateMap[x-1 + y*self.mapWidth] != 17):
  1146. self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1147. self.plotTypes[x + (y-1)*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1148. #Force Arabia
  1149. for x in range(self.mapWidth):
  1150. for y in range(self.mapHeight):
  1151. if self.plateMap[x + y*self.mapWidth] == 15:
  1152. if self.plateMap[x + (y-1)*self.mapWidth] != 15:
  1153. self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1154. self.plotTypes[x + (y-1)*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1155. if self.plateMap[x+1 + y*self.mapWidth] != 15:
  1156. self.plotTypes[x + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1157. self.plotTypes[x+1 + y*self.mapWidth] = PlotTypes.PLOT_OCEAN
  1158. #Force Central America
  1159. baseX = self.mapWidth/6
  1160. x = baseX
  1161. width = 2
  1162. if (self.dice.get(10,"Width variation") > 8):
  1163. width += 1
  1164. if (width > 1 and self.dice.get(10,"Width variation") > 8):
  1165. width -= 1
  1166. for y in range(self.mapHeight/5,self.mapHeight*3/4):
  1167. x = x + self.dice.get(3,"Not too straight") - 1
  1168. if ( x - baseX > 4):
  1169. x = baseX + 4
  1170. if ( x - baseX < -4):
  1171. x = baseX - 4
  1172. if (self.plotTypes[x + y*self.mapWidth ] == PlotTypes.PLOT_OCEAN):
  1173. for plot in range( width ):
  1174. self.plotTypes[x + y*self.mapWidth + plot ] = PlotTypes.PLOT_LAND
  1175. if (self.dice.get(10,"Some hills") > 5):
  1176. self.plotTypes[x + y*self.mapWidth + plot ] = PlotTypes.PLOT_HILLS
  1177. def movePlates(self,dontMoveSeaPlates):
  1178. plates = self.numContinents + self.numSeaPlates
  1179. if dontMoveSeaPlates:
  1180. xMoves = [0, 1, 0, 0, 0, 0, 0, 0, -1,-1, 0,-1, 0, 0,-1, 0,-1, 1, 1, 0, 0]
  1181. yMoves = [0, 0, 0, 0,-1, 1, 1, 0, 0, 1,-1,-1, 0, 1, 0, 0, 0, 1, 0, 0, 0]
  1182. subduction = [0, 9, 9, 0, 9, 0, 0, 0, 9, 9, 9, 0, 0, 9, 9, 9, 0, 9, 9, 0, 0]
  1183. else:
  1184. xMoves = [0, 1, 0, 0, 0, 1,-1, 0, -1,-1, 0, 1, 1,-1, 1, 0, 0,-1,-1, 1,-1]
  1185. yMoves = [0, 0, 0, 0, 1,-1, 0, 0, -1, 1,-1,-1, 1,-1,-1,-1,-1,-1, 0, 1, 1]
  1186. subduction = [0, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 9, 0, 9, 9, 9, 0, 0, 9, 0, 0]
  1187. self.doMovePlates(xMoves,yMoves,subduction)
  1188. class voronoiPangaeaMap(voronoiMap):
  1189. def __init__(self,numPlayers):
  1190. voronoiMap.__init__(self,numPlayers,1,1600)
  1191. self.peakAltitude = 11
  1192. self.hillAltitude = 7
  1193. self.landAltitude = 3
  1194. self.altitudeVariation = 3
  1195. def sowSeeds(self):
  1196. self.yTilt = self.dice.get(4,"YTilt")
  1197. self.plate[0] = 0
  1198. self.plate[1] = 0
  1199. for x in range(self.mapWidth):
  1200. self.plateMap[x] = 1
  1201. self.plateMap[self.mapWidth + x] = 1
  1202. self.plateMap[(self.mapHeight - 2)*self.mapWidth + x] = 1
  1203. self.plateMap[(self.mapHeight - 1)*self.mapWidth + x] = 1
  1204. for y in range(self.mapHeight):
  1205. self.plateMap[y*self.mapWidth] = 1
  1206. self.plateMap[y*self.mapWidth + 1] = 1
  1207. self.plateMap[y*self.mapWidth + self.mapWidth - 2] = 1
  1208. self.plateMap[y*self.mapWidth + self.mapWidth - 1] = 1
  1209. for i in range(self.numContinents):
  1210. self.plate[i + self.numSeaPlates] = 4 + self.dice.get(3,"Land altitude")
  1211. x, y = self.getCoord(i)
  1212. while self.plateMap[y*self.mapWidth + x] != 0:
  1213. x, y = self.getCoord(i)
  1214. self.plateMap[y*self.mapWidth + x] = i + 2
  1215. def getCoord(self,i):
  1216. step = self.mapWidth/(2*self.numContinents)
  1217. x = self.mapWidth/4 + i*step + self.dice.get(step,"x seed for plate")
  1218. quarterHeight = self.mapHeight/4
  1219. eigthHeight = self.mapHeight/8
  1220. y = quarterHeight + self.dice.get(self.mapHeight/2,"y seed for plate")
  1221. if (self.yTilt == 0):
  1222. y += i*(self.mapHeight/(self.numContinents*4)) - eigthHeight
  1223. elif (self.yTilt == 1):
  1224. y += eigthHeight - i*quarterHeight/self.numContinents
  1225. elif (self.yTilt == 2):
  1226. if (i%2 == 0):
  1227. y += eigthHeight
  1228. else:
  1229. y -= eigthHeight
  1230. # else: Let it be the way it was generated
  1231. return x, y
  1232. class ClimateGenerator:
  1233. def __init__(self):
  1234. self.climate = mapOptionAridity
  1235. self.map = gc.getMap()
  1236. self.mapWidth = self.map.getGridWidth()
  1237. if (self.climate == 0): # Arid
  1238. self.maxWindForce = self.mapWidth / 12
  1239. elif (self.climate == 1): # Normal
  1240. self.maxWindForce = self.mapWidth / 8
  1241. elif (self.climate == 2): # Wet
  1242. self.maxWindForce = self.mapWidth / 6
  1243. elif (self.climate == 3): # No ice
  1244. self.maxWindForce = self.mapWidth / 8
  1245. self.mapHeight = self.map.getGridHeight()
  1246. self.terrainDesert = mst.etDesert
  1247. self.terrainPlains = mst.etPlains
  1248. self.terrainIce = mst.etSnow
  1249. self.terrainTundra = mst.etTundra
  1250. self.terrainGrass = mst.etGrass
  1251. if (self.climate == 3): # No ice
  1252. self.terrainIce = mst.etTundra
  1253. self.terrainTundra = mst.etGrass
  1254. self.terrain = [0] * (self.mapWidth*self.mapHeight)
  1255. self.moisture = [0] * (self.mapWidth*self.mapHeight)
  1256. self.dice = gc.getGame().getMapRand()
  1257. def getLatitudeAtPlot(self, iX, iY):
  1258. "returns a value in the range of 0-90 degrees"
  1259. if (mapOptionLandmass == 5): # "Mediterranean"
  1260. return 65 - (40 * (self.mapHeight - iY) / self.mapHeight)
  1261. return self.map.plot(iX,iY).getLatitude()
  1262. def generateTerrain(self):
  1263. self.blowWinds()
  1264. self.blur()
  1265. self.computeTerrain()
  1266. return self.terrain
  1267. def computeTerrain(self):
  1268. terrain = [0] * (self.mapWidth*self.mapHeight)
  1269. for x in range(self.mapWidth):
  1270. for y in range(self.mapHeight):
  1271. if (self.map.plot(x,y).isWater()):
  1272. self.terrain[y*self.mapWidth+x] = self.map.plot(x,y).getTerrainType()
  1273. else:
  1274. terrain[y*self.mapWidth+x] = self.getTerrain(self.getLatitudeAtPlot(x,y),self.moisture[y*self.mapWidth + x])
  1275. for x in range(self.mapWidth):
  1276. for y in range(self.mapHeight):
  1277. if (not self.map.plot(x,y).isWater()):
  1278. i = y*self.mapWidth+x
  1279. self.terrain[i] = terrain[i]
  1280. bias = self.dice.get(3,"Random terrain")
  1281. if bias == 0 and y > 1:
  1282. self.terrain[i] = terrain[i-self.mapWidth]
  1283. if bias == 2 and y < self.mapHeight - 1:
  1284. self.terrain[i] = terrain[i+self.mapWidth]
  1285. for x in range(self.mapWidth):
  1286. for y in range(self.mapHeight):
  1287. if (not self.map.plot(x,y).isWater()):
  1288. i = y*self.mapWidth+x
  1289. if self.terrain[i] == self.terrainDesert:
  1290. if y > 1 and y < self.mapHeight - 1:
  1291. if self.terrain[i-self.mapWidth] == self.terrainGrass:
  1292. self.terrain[i-self.mapWidth] = self.terrainPlains
  1293. if self.terrain[i+self.mapWidth] == self.terrainGrass:
  1294. self.terrain[i+self.mapWidth] = self.terrainPlains
  1295. if self.terrain[i-1] == self.terrainGrass:
  1296. self.terrain[i-1] = self.terrainPlains
  1297. if self.terrain[i+1] == self.terrainGrass:
  1298. self.terrain[i+1] = self.terrainPlains
  1299. def getArcticTerrain(self, climate, latitude, moisture):
  1300. polar = 0
  1301. if (latitude > 70):
  1302. polar = latitude - 70
  1303. climate.ice += polar * polar * 3
  1304. climate.tundra += polar * (2 + moisture)
  1305. def getColdTerrain(self, climate, latitude, moisture):
  1306. if (latitude > 60):
  1307. polar = latitude - 60
  1308. climate.tundra += polar * (5 + moisture) + self.dice.get(polar*3,"more tundra")
  1309. if (moisture > 10):
  1310. climate.plains += polar * (moisture - 10)
  1311. def getTemperateTerrain(self, climate, latitude, moisture):
  1312. temperate = 45 - abs(45 - latitude)
  1313. climate.plains += temperate * (3 + moisture/2)
  1314. climate.grass += temperate * (1 + moisture) + self.dice.get(temperate,"more grass")
  1315. def getTropicalTerrain(self, climate, latitude, moisture):
  1316. tropical = 0
  1317. if (latitude < 40):
  1318. tropical = 20 - abs(20 - latitude)
  1319. climate.plains += tropical * (12 - self.climate + moisture/2) + self.dice.get(tropical,"more plains")
  1320. climate.grass += tropical * (moisture + self.climate)
  1321. climate.desert += tropical * (4 - self.climate) * 6
  1322. def getEquatorialTerrain(self, climate, latitude, moisture):
  1323. equator = 0
  1324. if (latitude < 25):
  1325. equator = 25 - latitude
  1326. climate.plains += equator * 7
  1327. climate.grass += equator * (3 + moisture) + self.dice.get(equator,"more grass")
  1328. #I compute latitude as in the maputil but wtf is there a plot.latitude then?
  1329. def getTerrain(self, latitude, moisture):
  1330. class climates:
  1331. def __init__(self):
  1332. self.ice = 0
  1333. self.tundra = 0
  1334. self.plains = 0
  1335. self.grass = 0
  1336. self.desert = 0
  1337. climate = climates()
  1338. self.getArcticTerrain(climate, latitude, moisture)
  1339. self.getColdTerrain(climate, latitude, moisture)
  1340. self.getTemperateTerrain(climate, latitude, moisture)
  1341. self.getTropicalTerrain(climate, latitude, moisture)
  1342. self.getEquatorialTerrain(climate, latitude, moisture)
  1343. if (climate.ice >= climate.tundra) and (climate.ice >= climate.plains) and (climate.ice >= climate.grass) and (climate.ice >= climate.desert):
  1344. return self.terrainIce
  1345. if (climate.tundra >= climate.plains) and (climate.tundra >= climate.grass) and (climate.tundra >= climate.desert):
  1346. return self.terrainTundra
  1347. if (climate.plains >= climate.grass) and (climate.plains >= climate.desert):
  1348. return self.terrainPlains
  1349. if (climate.grass >= climate.desert):
  1350. return self.terrainGrass
  1351. return self.terrainDesert
  1352. def blowWinds(self):
  1353. #Must find where the wind blows from and add moisture from there.
  1354. #If there is a mountain in between, then terrain must become more arid:
  1355. # Tundra -> ice (mmmh?), and grass -> plain -> desert.
  1356. for x in range(self.mapWidth):
  1357. for y in range(self.mapHeight):
  1358. if (self.map.plot(x,y).isWater()):
  1359. self.windBlowsFrom(x,y)
  1360. def windBlowsFrom(self,x,y):
  1361. latitude = self.getLatitudeAtPlot(x,y)
  1362. horizontal = 0
  1363. if (latitude > 80):
  1364. horizontal = 1
  1365. elif (latitude > 45):
  1366. horizontal = -1
  1367. elif (latitude > 30):
  1368. horizontal = 1
  1369. elif (latitude > 10):
  1370. horizontal = -1
  1371. else:
  1372. horizontal = 1
  1373. vertical = self.getVerticalWind(latitude,y)
  1374. windForce = 1 + self.dice.get(self.maxWindForce,"Wind force")
  1375. localMoisture = 5 + self.maxWindForce
  1376. self.blow(localMoisture,windForce,horizontal,vertical,x,y)
  1377. def getVerticalWind(self,latitude,y):
  1378. if (latitude>70):
  1379. vertical = -1
  1380. elif (latitude>30):
  1381. vertical = 1
  1382. else:
  1383. vertical = -1
  1384. if (2*y < self.mapHeight):
  1385. vertical *= -1
  1386. return vertical
  1387. def blow(self,localMoisture,maxHorizontal,horizontal,vertical,x,y):
  1388. plotType = self.map.plot(x,y).getPlotType()
  1389. if (y+vertical > 0 and y+vertical < self.mapHeight):
  1390. if (plotType != PlotTypes.PLOT_PEAK):
  1391. if (plotType == PlotTypes.PLOT_HILLS):
  1392. self.blow(localMoisture - 7,maxHorizontal-2,horizontal,vertical,x,y+vertical)
  1393. else:
  1394. self.blow(localMoisture - 1,maxHorizontal-2,horizontal,vertical,x,y+vertical)
  1395. for i in range(-1,maxHorizontal):
  1396. adjustedX = x + i*horizontal
  1397. if (adjustedX < 0):
  1398. adjustedX += self.mapWidth
  1399. elif (adjustedX >= self.mapWidth):
  1400. adjustedX -= self.mapWidth
  1401. self.moisture[y*self.mapWidth + adjustedX] = self.moisture[y*self.mapWidth + adjustedX] + localMoisture
  1402. plotType = self.map.plot(adjustedX,y).getPlotType()
  1403. if (plotType == PlotTypes.PLOT_PEAK):
  1404. return
  1405. elif (plotType == PlotTypes.PLOT_HILLS):
  1406. localMoisture -= 7
  1407. else:
  1408. localMoisture -= 1
  1409. if (localMoisture <= 0):
  1410. return
  1411. def blur(self):
  1412. max = 1
  1413. for y in range(self.mapHeight):
  1414. for x in range(self.mapWidth):
  1415. i = y*self.mapWidth + x
  1416. if (max < self.moisture[i]):
  1417. max = self.moisture[i]
  1418. for y in range(1,self.mapHeight-2):
  1419. for x in range(self.mapWidth):
  1420. i = y*self.mapWidth + x
  1421. self.moisture[i] = self.moisture[i]*100/max
  1422. #
  1423. # Main landmass/landscape generation function
  1424. #
  1425. def generatePlotTypes():
  1426. "Generates a map with several continents and a few islands."
  1427. print "-- generatePlotTypes()"
  1428. numPlayers = gc.getGame().countCivPlayersEverAlive()
  1429. surface = gc.getMap().getGridWidth() * gc.getMap().getGridHeight()
  1430. numPlayers = (numPlayers + surface / 400) / 2
  1431. numContinents = 1
  1432. numSeaPlates = 1
  1433. hotspotsFrequency = 900
  1434. if (mapOptionLandmass == 0): # "Earthlike (70% water)"
  1435. numContinents = 1 + numPlayers*2
  1436. numSeaPlates = numPlayers*3 - 1
  1437. hotspotsFrequency = 900
  1438. generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
  1439. elif (mapOptionLandmass == 1): # "Continental (60% water)"
  1440. numContinents = 1 + numPlayers*5/2
  1441. numSeaPlates = numPlayers*5/2 - 1
  1442. hotspotsFrequency = 1100
  1443. generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
  1444. elif (mapOptionLandmass == 3): # "Lakes (30% water")
  1445. numContinents = 1 + numPlayers*5
  1446. numSeaPlates = numPlayers - 1
  1447. hotspotsFrequency = 1900
  1448. generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
  1449. elif (mapOptionLandmass == 2): # "Pangaea"
  1450. generator = voronoiPangaeaMap(numPlayers)
  1451. elif (mapOptionLandmass == 4): # "Islands (85% Water)"
  1452. numContinents = 1 + numPlayers
  1453. numSeaPlates = numPlayers*6 - 1
  1454. hotspotsFrequency = 700
  1455. generator = voronoiMap(numContinents,numSeaPlates,hotspotsFrequency)
  1456. elif (mapOptionLandmass == 5): # "Mediterranean"
  1457. generator = voronoiMediterraneanMap(numPlayers)
  1458. elif (mapOptionLandmass == 6 or mapOptionLandmass == 7): # "Terra"
  1459. generator = voronoiTerraMap()
  1460. plotTypes = generator.generate()
  1461. # Print plotMap and differencePlotMap
  1462. mst.mapPrint.buildPlotMap( True, "generatePlotTypes()", data=plotTypes )
  1463. if mapOptionLandscape == 0: # option Planetfall Highlands
  1464. # 'Planetfall' uses ridges/highlands, the original Planetfall landscape generator will be used
  1465. plotTypes = planetfallGenerateHighlands( plotTypes )
  1466. elif mapOptionLandscape == 1: # option Tectonic Highlands
  1467. # 'Planetfall' uses ridges/highlands, some hills and peaks will be added
  1468. plotTypes = mst.planetFallMap.buildPfallHighlands( data=plotTypes )
  1469. return plotTypes
  1470. # Generate highland terrain for Planetfall - from planetfall.py mostly
  1471. def planetfallGenerateHighlands( plotTypes ):
  1472. print "-- planetfallGenerateHighlands()"
  1473. NiTextOut("Setting Plot Types (Python PlanetFall Highlands) ...")
  1474. #-------------------------------------------------------------------------
  1475. # Finetuning Constants
  1476. #
  1477. # Amount of Highlands.
  1478. # Range [1, 100] (I think)
  1479. # Higher number means LESS.
  1480. h_highlands = 60
  1481. # Lower grain will i.g. produce more coherent areas.
  1482. # Range [1, ->].
  1483. # Values below 4 are likey to produce just one big blobb...
  1484. h_grain = 4
  1485. # Amount of Peaks. Is derived from amount of highlands, hence as fraction
  1486. # Range [0, 1]
  1487. # 0 ~ no Peaks. 1 will probably cover all the map with them.
  1488. # Here more means more. Sorry.
  1489. h_peaks = 0.25
  1490. iW = map.getGridWidth()
  1491. iH = map.getGridHeight()
  1492. # plotTypes = [PlotTypes.PLOT_OCEAN] * (iW*iH)
  1493. terrainFrac = CyFractal()
  1494. # fractal_world = PFHL_MultilayeredFractal()
  1495. # plotTypes = fractal_world.generatePlotsByRegion()
  1496. terrainFrac.fracInit(iW, iH, h_grain, dice, 0, -1, -1)
  1497. iHighlandThreshold = terrainFrac.getHeightFromPercent(h_highlands)
  1498. iPeaksThreshold = iHighlandThreshold - (iHighlandThreshold * h_peaks)
  1499. # Now the main loop, which will assign the plot types.
  1500. for x in range(iW):
  1501. for y in range(iH):
  1502. i = y*iW + x
  1503. val = terrainFrac.getHeight(x,y)
  1504. if plotTypes[i] == PlotTypes.PLOT_OCEAN:
  1505. continue # Water plots already set.
  1506. if val >= iHighlandThreshold:
  1507. plotTypes[i] = PlotTypes.PLOT_HILLS
  1508. elif val >= iPeaksThreshold and val < iHighlandThreshold:
  1509. plotTypes[i] = PlotTypes.PLOT_PEAK
  1510. else:
  1511. pass
  1512. return plotTypes
  1513. #Rivers map second try...
  1514. class riversMap:
  1515. def __init__(self):
  1516. self.gc = CyGlobalContext()
  1517. self.dice = gc.getGame().getMapRand()
  1518. self.map = CyMap()
  1519. self.mapWidth = self.map.getGridWidth()
  1520. self.mapHeight = self.map.getGridHeight()
  1521. self.file = open( "d:\\tmp\\toto.txt", 'w' )
  1522. self.generateHeightMap()
  1523. def initHeightMap(self,currentLands):
  1524. #initialize with high altitudes on peaks and hills
  1525. for x in range(self.mapWidth):
  1526. for y in range(self.mapHeight):
  1527. plot = self.map.plot(x,y)
  1528. if (plot.getPlotType() == PlotTypes.PLOT_PEAK):
  1529. currentLands[x + y*self.mapWidth] = 1
  1530. self.heightMap[x + y*self.mapWidth] = 10000
  1531. elif (plot.getPlotType() == PlotTypes.PLOT_HILLS):
  1532. currentLands[x + y*self.mapWidth] = 1
  1533. self.heightMap[x + y*self.mapWidth] = 1000
  1534. elif (plot.getPlotType() == PlotTypes.PLOT_LAND):
  1535. currentLands[x + y*self.mapWidth] = 1
  1536. self.heightMap[x + y*self.mapWidth] = 1
  1537. def generateHeightMap(self):
  1538. self.heightMap = [0] * (self.mapWidth*self.mapHeight)
  1539. currentLands = [0] * (self.mapWidth*self.mapHeight)
  1540. self.initHeightMap(currentLands)
  1541. finished = false
  1542. #make sure there's a slope towards seas and lakes
  1543. while not finished:
  1544. finished = true
  1545. buffer = [1] * (self.mapWidth*self.mapHeight)
  1546. for x in range(self.mapWidth):
  1547. for y in range(self.mapHeight):
  1548. plot = x + y*self.mapWidth
  1549. if currentLands[plot] == 0:
  1550. buffer[plot] = 0
  1551. for i in self.neighbours(x, y):
  1552. buffer[i] = 0
  1553. for x in range(self.mapWidth):
  1554. for y in range(self.mapHeight):
  1555. plot = x + y*self.mapWidth
  1556. currentLands[plot] = buffer[plot]
  1557. if buffer[plot] == 1:
  1558. finished = false
  1559. self.heightMap[plot] = 1 + self.heightMap[plot]
  1560. #make sure there's a slope going downwards away from mountains
  1561. for i in range(20):
  1562. increase = []
  1563. for x in range(self.mapWidth):
  1564. for y in range(self.mapHeight):
  1565. if self.heightMap[x + y*self.mapWidth] > 20 - i:
  1566. for j in self.neighbours(x, y):
  1567. increase.append(j)
  1568. for plot in increase:
  1569. self.heightMap[plot] = self.heightMap[plot] + 2
  1570. for y in range(self.mapHeight):
  1571. for x in range(self.mapWidth):
  1572. plot = x + y*self.mapWidth
  1573. self.file.write( str( self.heightMap[plot] ) + "\t" )
  1574. self.file.write( "\n" )
  1575. def neighbours(self, x, y):
  1576. result = []
  1577. if x == 0:
  1578. result.append(y*self.mapWidth)
  1579. else:
  1580. result.append(x-1 + y*self.mapWidth)
  1581. if x == self.mapWidth - 1:
  1582. result.append(y*self.mapWidth)
  1583. else:
  1584. result.append(x+1 + y*self.mapWidth)
  1585. if y > 0:
  1586. result.append(x + (y-1)*self.mapWidth)
  1587. if y < self.mapHeight - 1:
  1588. result.append(x + (y+1)*self.mapWidth)
  1589. return result
  1590. def seedRivers(self):
  1591. climate = mapOptionAridity
  1592. if (climate == 0): # Arid
  1593. divider = 6
  1594. elif (climate == 1): # Normal
  1595. divider = 3
  1596. elif (climate == 2): # Wet
  1597. divider = 2
  1598. elif (climate == 3): # No ice
  1599. divider = 3
  1600. probability = 30/divider
  1601. seeds = []
  1602. for x in range(self.mapWidth):
  1603. for y in range(self.mapHeight):
  1604. plot = self.map.plot(x,y)
  1605. if (plot.getPlotType() == PlotTypes.PLOT_HILLS):
  1606. if self.dice.get(100,"Start river") < probability:
  1607. seeds.append( plot )
  1608. elif (plot.getPlotType() == PlotTypes.PLOT_LAND):
  1609. if self.dice.get(1000,"Start river in flatland") < probability + self.heightMap[x + y*self.mapWidth]:
  1610. seeds.append( plot )
  1611. for plot in seeds:
  1612. riverID = self.gc.getMap().getNextRiverID()
  1613. self.startRiver(riverID, plot)
  1614. self.file.close()
  1615. def startRiver(self, riverID, plot):
  1616. if plot.isWater():
  1617. return true
  1618. x = plot.getX()
  1619. y = plot.getY()
  1620. height = self.heightMap[x + y * self.mapWidth]
  1621. ns = self.checkNorthSouth(x, y, height)
  1622. ew = self.checkEastWest(x, y, height)
  1623. if ns == CardinalDirectionTypes.NO_CARDINALDIRECTION and ew == CardinalDirectionTypes.NO_CARDINALDIRECTION:
  1624. self.file.write( "End river false\n" )
  1625. return false
  1626. self.file.write( "Will flow\n" )
  1627. if ns != CardinalDirectionTypes.NO_CARDINALDIRECTION and ew != CardinalDirectionTypes.NO_CARDINALDIRECTION:
  1628. if self.dice.get(self.mapHeight + self.mapWidth,"direction") < self.mapHeight:
  1629. self.flow(riverID, plot, ns)
  1630. else:
  1631. self.flow(riverID, plot, ew)
  1632. elif ns != CardinalDirectionTypes.NO_CARDINALDIRECTION:
  1633. self.flow(riverID, plot, ns)
  1634. elif ew != CardinalDirectionTypes.NO_CARDINALDIRECTION:
  1635. self.flow(riverID, plot, ew)
  1636. self.file.write( "End river true\n" )
  1637. return true
  1638. #checks for isWOfRiver
  1639. def checkNorthSouth(self, x, y, height):
  1640. if x == self.mapWidth - 1:
  1641. delta = 1 - self.mapWidth
  1642. else:
  1643. delta = 1
  1644. west = x + delta + y*self.mapWidth
  1645. northSouthHeight = height + self.heightMap[west]
  1646. result = CardinalDirectionTypes.NO_CARDINALDIRECTION
  1647. plot = self.map.plot(x,y)
  1648. if plot.isWOfRiver():
  1649. return result
  1650. if y > 0:
  1651. nHeight = self.heightMap[x + (y-1)*self.mapWidth] + self.heightMap[x + delta + (y-1)*self.mapWidth]
  1652. self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(nHeight) + " <? " + str(northSouthHeight) + "\n" )
  1653. if nHeight < northSouthHeight:
  1654. result = CardinalDirectionTypes.CARDINALDIRECTION_SOUTH
  1655. if y < self.mapHeight -1:
  1656. sHeight = self.heightMap[x + (y-1)*self.mapWidth] + self.heightMap[x + delta + (y-1)*self.mapWidth]
  1657. self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(sHeight) + " <? " + str(northSouthHeight) + "\n" )
  1658. if sHeight < northSouthHeight:
  1659. if result == CardinalDirectionTypes.NO_CARDINALDIRECTION or sHeight < nHeight:
  1660. result = CardinalDirectionTypes.CARDINALDIRECTION_NORTH
  1661. return result
  1662. #checks for isNOfRiver
  1663. def checkEastWest(self, x, y, height):
  1664. result = CardinalDirectionTypes.NO_CARDINALDIRECTION
  1665. plot = self.map.plot(x,y)
  1666. if plot.isNOfRiver():
  1667. return result
  1668. if y < self.mapHeight -1:
  1669. south = x + (y+1)*self.mapWidth
  1670. eastWestHeight = height + self.heightMap[south]
  1671. if x == self.mapWidth - 1:
  1672. west = y*self.mapWidth
  1673. swest = (y+1)*self.mapWidth
  1674. else:
  1675. west = x + 1 + y*self.mapWidth
  1676. swest = x + 1 + (y+1)*self.mapWidth
  1677. wHeight = self.heightMap[west] + self.heightMap[swest]
  1678. self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(wHeight) + " <? " + str(eastWestHeight) + "\n" )
  1679. if wHeight < eastWestHeight:
  1680. result = CardinalDirectionTypes.CARDINALDIRECTION_WEST
  1681. if x == 0:
  1682. east = y*self.mapWidth
  1683. seast = (y+1)*self.mapWidth
  1684. else:
  1685. east = x - 1 + y*self.mapWidth
  1686. seast = x - 1 + (y+1)*self.mapWidth
  1687. eHeight = self.heightMap[east] + self.heightMap[seast]
  1688. self.file.write( " For " + str(x) + ", " + str(y) + ", heights: " + str(eHeight) + " <? " + str(eastWestHeight) + "\n" )
  1689. if eHeight < eastWestHeight:
  1690. if result == CardinalDirectionTypes.NO_CARDINALDIRECTION or eHeight < wHeight:
  1691. result = CardinalDirectionTypes.CARDINALDIRECTION_EAST
  1692. return result
  1693. def joins(self, riverPlot, riverID):
  1694. return (riverPlot.isWOfRiver() or riverPlot.isNOfRiver()) and riverPlot.getRiverID() != riverID
  1695. def flow(self, riverID, plot, direction):
  1696. x = plot.getX()
  1697. y = plot.getY()
  1698. self.file.write( "Flow to " + str(x) + ", " + str(y) + "\n" )
  1699. if direction == CardinalDirectionTypes.CARDINALDIRECTION_EAST:
  1700. if x < self.mapWidth - 1:
  1701. riverPlot = self.map.plot(x+1,y)
  1702. if y == self.mapHeight - 1 or self.map.plot(x+1,y+1).isWater() or riverPlot.isWater():
  1703. return
  1704. else:
  1705. riverPlot = self.map.plot(0,y)
  1706. if y == self.mapHeight - 1 or self.map.plot(0,y+1).isWater() or riverPlot.isWater():
  1707. return
  1708. joinRiver = self.joins(riverPlot, riverID)
  1709. riverPlot.setNOfRiver(True,direction)
  1710. if direction == CardinalDirectionTypes.CARDINALDIRECTION_WEST:
  1711. if x > 0:
  1712. riverPlot = self.map.plot(x-1,y)
  1713. if y == self.mapHeight - 1 or self.map.plot(x-1,y+1).isWater() or riverPlot.isWater():
  1714. return
  1715. else:
  1716. riverPlot = self.map.plot(self.mapWidth-1,y)
  1717. if y == self.mapHeight - 1 or self.map.plot(self.mapWidth-1,y+1).isWater() or riverPlot.isWater():
  1718. return
  1719. joinRiver = self.joins(riverPlot, riverID)
  1720. riverPlot.setNOfRiver(True,direction)
  1721. if direction == CardinalDirectionTypes.CARDINALDIRECTION_NORTH:
  1722. riverPlot = self.map.plot(x,y-1)
  1723. 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():
  1724. return
  1725. joinRiver = self.joins(riverPlot, riverID)
  1726. riverPlot.setWOfRiver(True,direction)
  1727. if direction == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH:
  1728. riverPlot = self.map.plot(x,y+1)
  1729. 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():
  1730. return
  1731. joinRiver = self.joins(riverPlot, riverID)
  1732. riverPlot.setWOfRiver(True,direction)
  1733. if joinRiver:
  1734. self.file.write( "Joining rivers\n" )
  1735. return
  1736. riverPlot.setRiverID(riverID)
  1737. self.startRiver(riverID,riverPlot)
  1738. #if not self.startRiver(riverID,riverPlot):
  1739. #self.file.write( "Add ocean in " + str(riverPlot.getX()) + ", " + str(riverPlot.getY()) + "\n" )
  1740. #riverPlot.setPlotType(PlotTypes.PLOT_OCEAN,true,true)
  1741. # This whole class is needlessly complex. It would be better to rewrite it by first defining
  1742. # a new map, which is the map of the places between squares, giving them an altitude which would be the max
  1743. # of the surrounding squares. This would simplify this a lot but I'm too lazy for now to rewrite all.
  1744. class riversFromSea:
  1745. def __init__(self):
  1746. self.gc = CyGlobalContext()
  1747. self.dice = self.gc.getGame().getMapRand()
  1748. self.map = CyMap()
  1749. self.width = self.map.getGridWidth()
  1750. self.height = self.map.getGridHeight()
  1751. self.straightThreshold = 4
  1752. self.riverLength = {}
  1753. self.riverTurns = {}
  1754. self.minRiverLength = self.height/6
  1755. if (self.width * self.height > 400):
  1756. self.straightThreshold = 3
  1757. def seedRivers(self):
  1758. climate = mapOptionAridity
  1759. if (climate == 0): # Arid
  1760. divider = 4
  1761. elif (climate == 1): # Normal
  1762. divider = 2
  1763. elif (climate == 2): # Wet
  1764. divider = 1
  1765. elif (climate == 3): # No ice
  1766. divider = 2
  1767. maxNumber = (self.width + self.height) / divider
  1768. riversNumber = 1 + maxNumber
  1769. if (mapOptionLandmass == 1): # Pangaea
  1770. riversNumber = maxNumber/2
  1771. self.coasts = self.collateCoasts()
  1772. coastsNumber = len(self.coasts)
  1773. if (coastsNumber == 0):
  1774. return
  1775. coastShare = coastsNumber/riversNumber
  1776. for i in range(riversNumber):
  1777. flow = CardinalDirectionTypes.NO_CARDINALDIRECTION
  1778. tries = 0
  1779. while flow == CardinalDirectionTypes.NO_CARDINALDIRECTION and tries < 6:
  1780. tries = tries + 1
  1781. (x,y,flow) = self.generateRiver(i,coastShare)
  1782. if flow != CardinalDirectionTypes.NO_CARDINALDIRECTION:
  1783. riverID = self.gc.getMap().getNextRiverID()
  1784. self.riverLength[riverID] = 0
  1785. self.riverTurns[riverID] = 0
  1786. self.addRiverFrom(x,y,flow,riverID)
  1787. def collateCoasts(self):
  1788. result = []
  1789. for x in range(self.width):
  1790. for y in range(self.height):
  1791. plot = self.map.plot(x,y)
  1792. if (plot.isCoastalLand()):
  1793. result.append(plot)
  1794. return result
  1795. def generateRiver(self,i,coastShare):
  1796. choiceCoast = coastShare * i + self.dice.get(coastShare,"Pick a coast for the river")
  1797. plot = self.coasts[choiceCoast]
  1798. FlowDirection = CardinalDirectionTypes.NO_CARDINALDIRECTION
  1799. x = plot.getX()
  1800. y = plot.getY()
  1801. if ((y < 1 or y >= self.height - 1) or plot.isNOfRiver() or plot.isWOfRiver()):
  1802. return (x,y,FlowDirection)
  1803. eastX = self.eastX(x)
  1804. westX = self.westX(x)
  1805. otherPlot = True
  1806. eastPlot = self.map.plot(eastX,y)
  1807. if (eastPlot.isCoastalLand()):
  1808. seaPlot = self.map.plot(x,y+1)
  1809. if ((self.map.plot(x,y+1).isWater()) or (self.map.plot(eastX,y+1).isWater())):
  1810. landPlot1 = self.map.plot(x,y-1)
  1811. landPlot2 = self.map.plot(eastX,y-1)
  1812. if (landPlot1.isWater() or landPlot2.isWater()):
  1813. otherPlot = True
  1814. else:
  1815. FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_NORTH
  1816. otherPlot = False
  1817. if (otherPlot == True):
  1818. if ((self.map.plot(x,y-1).isWater()) or (self.map.plot(eastX,y-1).isWater())):
  1819. landPlot1 = self.map.plot(x,y+1)
  1820. landPlot2 = self.map.plot(eastX,y+1)
  1821. if (landPlot1.isWater() or landPlot2.isWater()):
  1822. otherPlot = True
  1823. else:
  1824. FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_SOUTH
  1825. otherPlot = False
  1826. if (otherPlot == True):
  1827. southPlot = self.map.plot(x,y-1)
  1828. if (southPlot.isCoastalLand()):
  1829. if ((self.map.plot(eastX,y).isWater()) or (self.map.plot(eastX,y-1).isWater())):
  1830. landPlot1 = self.map.plot(westX,y)
  1831. landPlot2 = self.map.plot(westX,y-1)
  1832. if (landPlot1.isWater() or landPlot2.isWater()):
  1833. otherPlot = True
  1834. else:
  1835. FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_EAST
  1836. otherPlot = False
  1837. if (otherPlot == True):
  1838. if ((self.map.plot(westX,y).isWater()) or (self.map.plot(westX,y-1).isWater())):
  1839. landPlot1 = self.map.plot(eastX,y)
  1840. landPlot2 = self.map.plot(eastX,y-1)
  1841. if (landPlot1.isWater() or landPlot2.isWater()):
  1842. otherPlot = True
  1843. else:
  1844. FlowDirection = CardinalDirectionTypes.CARDINALDIRECTION_WEST
  1845. return (x,y,FlowDirection)
  1846. # prevent rivers from crossing each other
  1847. def preventRiversFromCrossing(self,x,y,flow,riverID):
  1848. plot = self.map.plot(x,y)
  1849. eastX = self.eastX(x)
  1850. westX = self.westX(x)
  1851. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1852. if (plot.isNOfRiver()):
  1853. return true
  1854. if (self.map.plot(eastX,y).isNOfRiver()):
  1855. return true
  1856. southPlot = self.map.plot(x,y-1)
  1857. if (southPlot.isWOfRiver() and southPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
  1858. return true
  1859. if (plot.isWOfRiver() and plot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  1860. return true
  1861. if (self.map.plot(eastX,y).isWater()):
  1862. return true
  1863. if (self.map.plot(x,y-1).isWater()):
  1864. return true
  1865. if (self.map.plot(eastX,y-1).isWater()):
  1866. return true
  1867. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
  1868. if (plot.isNOfRiver()):
  1869. return true
  1870. if (self.map.plot(westX,y).isNOfRiver()):
  1871. return true
  1872. southPlot = self.map.plot(westX,y-1)
  1873. if (southPlot.isWOfRiver() and southPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
  1874. return true
  1875. westPlot = self.map.plot(westX,y)
  1876. if (westPlot.isWOfRiver() and westPlot.getRiverNSDirection() == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  1877. return true
  1878. if (self.map.plot(westX,y).isWater()):
  1879. return true
  1880. if (self.map.plot(x,y-1).isWater()):
  1881. return true
  1882. if (self.map.plot(westX,y-1).isWater()):
  1883. return true
  1884. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  1885. if (plot.isWOfRiver()):
  1886. return true
  1887. eastPlot = self.map.plot(eastX,y)
  1888. if (eastPlot.isNOfRiver() and eastPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
  1889. return true
  1890. if (plot.isNOfRiver() and plot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1891. return true
  1892. if (self.map.plot(x,y-1).isWOfRiver()):
  1893. return true
  1894. if (self.map.plot(x,y-1).isWater()):
  1895. return true
  1896. if (self.map.plot(x+1,y).isWater()):
  1897. return true
  1898. if (self.map.plot(x+1,y-1).isWater()):
  1899. return true
  1900. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
  1901. if (plot.isWOfRiver()):
  1902. return true
  1903. eastPlot = self.map.plot(eastX,y+1)
  1904. if (eastPlot.isNOfRiver() and eastPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
  1905. return true
  1906. northPlot = self.map.plot(x,y+1)
  1907. if (northPlot.isNOfRiver() and northPlot.getRiverWEDirection() == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1908. return true
  1909. if (self.map.plot(x,y+1).isWOfRiver()):
  1910. return true
  1911. if (self.map.plot(x,y+1).isWater()):
  1912. return true
  1913. if (self.map.plot(x+1,y).isWater()):
  1914. return true
  1915. if (self.map.plot(x+1,y+1).isWater()):
  1916. return true
  1917. return false
  1918. def addRiverFrom(self,x,y,flow,riverID):
  1919. plot = self.map.plot(x,y)
  1920. if (plot.isWater()):
  1921. return
  1922. self.riverLength[riverID] = self.riverLength[riverID] + 1
  1923. eastX = self.eastX(x)
  1924. westX = self.westX(x)
  1925. if (self.preventRiversFromCrossing(x,y,flow,riverID)):
  1926. return
  1927. plot.setRiverID(riverID)
  1928. if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
  1929. plot.setNOfRiver(True,flow)
  1930. else:
  1931. plot.setWOfRiver(True,flow)
  1932. xShift = 0
  1933. yShift = 0
  1934. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1935. xShift = 1
  1936. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST):
  1937. xShift = -1
  1938. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  1939. yShift = -1
  1940. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_SOUTH):
  1941. yShift = 1
  1942. nextX = x + xShift
  1943. nextY = y + yShift
  1944. if (nextX >= self.width):
  1945. nextX = 0
  1946. if (nextY >= self.height):
  1947. return
  1948. nextI = nextY*self.width + nextX
  1949. if (self.canFlowFrom(plot,self.map.plot(nextX,nextY)) == False):
  1950. return
  1951. if not mst.bPfall and plot.getTerrainType() == mst.etSnow and self.dice.get(10,"Stop on ice") > 3:
  1952. return
  1953. if mst.bPfall and (plot.getTerrainType() == mst.etFlatPolar or plot.getTerrainType() == mst.etRockyPolar) and self.dice.get(10,"Stop on ice") > 3:
  1954. return
  1955. flatDesert = plot.getPlotType() == PlotTypes.PLOT_LAND and \
  1956. ((not mst.bPfall and plot.getTerrainType() == mst.etDesert) or\
  1957. (mst.bPfall and (plot.getTerrainType() == mst.etFlatArid or plot.getTerrainType() == mst.etRockyArid)))
  1958. #Prevent Uturns in rivers
  1959. turnThreshold = 13
  1960. if flatDesert:
  1961. turnThreshold = 17
  1962. turned = False
  1963. northY = y + 1
  1964. southY = y - 1
  1965. if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
  1966. if ((northY < self.height) and (self.dice.get(20,"branch from north") > turnThreshold)):
  1967. nextI = northY*self.width + x
  1968. 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))):
  1969. turned = True
  1970. self.riverTurns[riverID] = self.riverTurns[riverID] + 1
  1971. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1972. self.addRiverFrom(x,y,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH,riverID)
  1973. else:
  1974. westPlot = self.map.plot(westX,y)
  1975. westPlot.setRiverID(riverID)
  1976. self.addRiverFrom(westX,y,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH,riverID)
  1977. if ((not turned) and (southY >= 0) and (self.dice.get(20,"branch from south") > turnThreshold)):
  1978. nextI = southY*self.width + x
  1979. 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))):
  1980. turned = True
  1981. self.riverTurns[riverID] = self.riverTurns[riverID] + 1
  1982. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST):
  1983. southPlot = self.map.plot(x,y-1)
  1984. southPlot.setRiverID(riverID)
  1985. self.addRiverFrom(x,southY,CardinalDirectionTypes.CARDINALDIRECTION_NORTH,riverID)
  1986. else:
  1987. westPlot = self.map.plot(westX,southY)
  1988. westPlot.setRiverID(riverID)
  1989. self.addRiverFrom(westX,southY,CardinalDirectionTypes.CARDINALDIRECTION_NORTH,riverID)
  1990. else:
  1991. nextI = y*self.width + eastX
  1992. 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)):
  1993. turned = True
  1994. self.riverTurns[riverID] = self.riverTurns[riverID] + 1
  1995. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  1996. eastPlot = self.map.plot(eastX,y)
  1997. eastPlot.setRiverID(riverID)
  1998. self.addRiverFrom(eastX,y,CardinalDirectionTypes.CARDINALDIRECTION_WEST,riverID)
  1999. else:
  2000. northEastPlot = self.map.plot(eastX,y+1)
  2001. northEastPlot.setRiverID(riverID)
  2002. self.addRiverFrom(eastX,y+1,CardinalDirectionTypes.CARDINALDIRECTION_WEST,riverID)
  2003. nextI = y*self.width + westX
  2004. 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)):
  2005. turned = True
  2006. if (flow == CardinalDirectionTypes.CARDINALDIRECTION_NORTH):
  2007. self.addRiverFrom(x,y,CardinalDirectionTypes.CARDINALDIRECTION_EAST,riverID)
  2008. else:
  2009. northPlot = self.map.plot(x,y+1)
  2010. northPlot.setRiverID(riverID)
  2011. self.addRiverFrom(x,y+1,CardinalDirectionTypes.CARDINALDIRECTION_EAST,riverID)
  2012. spawnInDesert = (not turned) and flatDesert
  2013. if ((self.dice.get(10,"straight river") > self.straightThreshold) or spawnInDesert):
  2014. if (not turned) or (self.riverTurns[riverID] * 5 < self.riverLength[riverID]):
  2015. self.addRiverFrom(nextX,nextY,flow,riverID)
  2016. else:
  2017. if (not turned):
  2018. if self.riverLength[riverID] < self.minRiverLength:
  2019. self.addRiverFrom(nextX,nextY,flow,riverID)
  2020. else:
  2021. plot = self.map.plot(nextX,nextY)
  2022. if ((plot.getPlotType() == PlotTypes.PLOT_LAND) and (self.dice.get(10,"Rivers start in hills") > 3)):
  2023. plot.setPlotType(PlotTypes.PLOT_HILLS,true,true)
  2024. if ((flow == CardinalDirectionTypes.CARDINALDIRECTION_WEST) or (flow == CardinalDirectionTypes.CARDINALDIRECTION_EAST)):
  2025. if southY > 0:
  2026. self.map.plot(nextX,southY).setPlotType(PlotTypes.PLOT_HILLS,true,true)
  2027. else:
  2028. self.map.plot(eastX,nextY).setPlotType(PlotTypes.PLOT_HILLS,true,true)
  2029. def canFlowFrom(self,plot,upperPlot):
  2030. if (plot.isWater()):
  2031. return False
  2032. if (plot.getPlotType() == PlotTypes.PLOT_PEAK):
  2033. return False
  2034. if (plot.getPlotType() == PlotTypes.PLOT_HILLS):
  2035. if ((upperPlot.getPlotType() == PlotTypes.PLOT_HILLS) or (upperPlot.getPlotType() == PlotTypes.PLOT_PEAK)):
  2036. return True
  2037. else:
  2038. return False
  2039. if (plot.getPlotType() == PlotTypes.PLOT_LAND):
  2040. if (upperPlot.isWater()):
  2041. return False
  2042. return True
  2043. def westX(self,x):
  2044. westX = x - 1
  2045. if (westX < 0):
  2046. westX = self.width
  2047. return westX
  2048. def eastX(self,x):
  2049. eastX = x + 1
  2050. if (eastX >= self.width):
  2051. eastX = 0
  2052. return eastX
  2053. # ------------------------------
  2054. # Temudjins Cool Starting Plots
  2055. # ------------------------------
  2056. # ensures that there are more than 3 land/hill plots within the central 3x3 grid
  2057. # and more than ok land/hill plots in the 5x5 grid around the starting-plot
  2058. def okLandPlots(xCoord, yCoord, ok=10):
  2059. land1 = 0
  2060. if ok >= 0:
  2061. for x in range( -2, 3 ):
  2062. for y in range( -2, 3 ):
  2063. plot = plotXY( xCoord, yCoord, x, y )
  2064. if not plot.isNone():
  2065. if plot.isHills() or plot.isFlatlands():
  2066. land1 += 1
  2067. if land1 > ok:
  2068. land2 = 0
  2069. for x in range( -1, 2 ):
  2070. for y in range( -1, 2 ):
  2071. plot = plotXY( xCoord, yCoord, x, y )
  2072. if not plot.isNone():
  2073. if plot.isHills() or plot.isFlatlands():
  2074. land2 += 1
  2075. if land2 > 3:
  2076. return True
  2077. return False
  2078. # ensures that plot isn't within ok plots from edge of the world
  2079. def okMapEdge( x, y, ok=3 ):
  2080. if not map.isWrapX():
  2081. if ( x < ok ) or ( x > (mst.iNumPlotsX-1-ok) ):
  2082. return False
  2083. if not map.isWrapY():
  2084. if ( y < ok ) or ( y > (mst.iNumPlotsY-1-ok) ):
  2085. return False
  2086. return True
  2087. # ----------------------------------
  2088. # END Temudjin's Cool Starting Plots
  2089. # ----------------------------------
  2090. # ######################################################################################################
  2091. # ######## assignStartingPlots() - Called from system
  2092. # ######## - assign starting positions for each player after the map is generated
  2093. # ######## - Planetfall has GameOption 'SCATTERED_LANDING_PODS' - use default implementation
  2094. # ######################################################################################################
  2095. def assignStartingPlots():
  2096. iPlayers = gc.getGame().countCivPlayersEverAlive()
  2097. if mst.bPfall:
  2098. CyPythonMgr().allowDefaultImpl()
  2099. else:
  2100. map.recalculateAreas()
  2101. areas = CvMapGeneratorUtil.getAreas()
  2102. areaValue = {}
  2103. allOnBest = false
  2104. isolatedStarts = false
  2105. if (mapOptionLandmass == 4): # "Islands"
  2106. isolatedStarts = true
  2107. if (mapOptionLandmass == 7): # "Terra"
  2108. allOnBest = true
  2109. for area in areas:
  2110. if area.isWater(): continue
  2111. areaValue[area.getID()] = area.calculateTotalBestNatureYield() + area.getNumRiverEdges() + 2 * area.countCoastalLand() + 3 * area.countNumUniqueBonusTypes()
  2112. # Shuffle players so the same player doesn't always get the first pick.
  2113. player_list = []
  2114. ########## Temudjin START
  2115. #for plrCheckLoop in range(18):
  2116. for plrCheckLoop in range( gc.getMAX_CIV_PLAYERS() ):
  2117. ########## Temudjin END
  2118. if gc.getPlayer(plrCheckLoop).isEverAlive():
  2119. player_list.append(plrCheckLoop)
  2120. shuffledPlayers = []
  2121. for playerLoop in range(iPlayers):
  2122. iChoosePlayer = dice.get(len(player_list), "Shuffling Players - Highlands PYTHON")
  2123. shuffledPlayers.append(player_list[iChoosePlayer])
  2124. del player_list[iChoosePlayer]
  2125. # Loop through players, assigning starts for each.
  2126. for assign_loop in range(iPlayers):
  2127. playerID = shuffledPlayers[assign_loop]
  2128. player = gc.getPlayer(playerID)
  2129. if (allOnBest):
  2130. #-----
  2131. def isValid(playerID, x, y):
  2132. pPlot = map.plot(x, y)
  2133. if (pPlot.getArea() != map.findBiggestArea(False).getID()):
  2134. return False
  2135. ########## Temudjin START
  2136. #return True
  2137. # Also check for Temudjin's cool starting plots
  2138. return ( okLandPlots(x,y,10) and okMapEdge(x,y,3) )
  2139. ########## Temudjin END
  2140. #-----
  2141. else:
  2142. bestAreaValue = 0
  2143. global bestArea
  2144. bestArea = -1
  2145. for area in areas:
  2146. if area.isWater(): continue
  2147. players = 2*area.getNumStartingPlots()
  2148. #Avoid single players on landmasses:
  2149. if (false == isolatedStarts and players == 0):
  2150. if (assign_loop == iPlayers - 1):
  2151. players = 4
  2152. else:
  2153. players = 2
  2154. value = areaValue[area.getID()] / (1 + 2*players )
  2155. if (value > bestAreaValue):
  2156. bestAreaValue = value;
  2157. bestArea = area.getID()
  2158. #-----
  2159. def isValid(playerID, x, y):
  2160. global bestArea
  2161. plot = map.plot(x,y)
  2162. if (plot.getArea() != bestArea):
  2163. return false
  2164. if (plot.getLatitude() >= 75):
  2165. return false
  2166. ########## Temudjin START
  2167. #return True
  2168. # Also check for Temudjin's cool starting plots
  2169. return ( okLandPlots(x,y,10) and okMapEdge(x,y,3) )
  2170. ########## Temudjin END
  2171. #-----
  2172. findstart = CvMapGeneratorUtil.findStartingPlot(playerID,isValid)
  2173. sPlot = map.plotByIndex(findstart)
  2174. player.setStartingPlot(sPlot,true)
  2175. class MediterraneanFeatureGenerator(CvMapGeneratorUtil.FeatureGenerator):
  2176. def getLatitudeAtPlot(self, iX, iY):
  2177. "returns 0.0 for tropical, up to 1.0 for polar"
  2178. # 25/90 to 65/90:
  2179. lat = 5/float(18) + 4*(self.iGridH - iY)/float(9*self.iGridH)
  2180. return lat
  2181. class NoIceFeatureGenerator(CvMapGeneratorUtil.FeatureGenerator):
  2182. def addIceAtPlot(self, pPlot, iX, iY, lat):
  2183. return
  2184. def addFloodPlains(plot):
  2185. if plot.isRiverSide() and plot.isFlatlands():
  2186. if (plot.getFeatureType() == FeatureTypes.NO_FEATURE):
  2187. for iI in range(gc.getNumFeatureInfos()):
  2188. if plot.canHaveFeature(iI):
  2189. if 10000 == gc.getFeatureInfo(iI).getAppearanceProbability():
  2190. plot.setFeatureType(iI, -1)