Erebus_mst.py 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805
  1. ## File: Erebus_mst.py (Creation.py)
  2. ## Author: Rich Marinaccio
  3. ## Copyright 2007 Rich Marinaccio
  4. ##############################################################################
  5. ## This map script is intended for use with the Fall from Heaven 2 mod for
  6. ## Civilization 4
  7. ##############################################################################
  8. ## Version History
  9. ## 1.07 - Added the sea level option. This option also changes the map size
  10. ## so that the play area remains the same. Added climate options. Added marsh
  11. ## terrain. Fixed a bug from 1.05 that created an unreachable ocean in the
  12. ## corner of the map somtimes.
  13. ##
  14. ## 1.06 - Added some of the new preferences for FfH 0.32 unique improvements.
  15. ## Improved the choke point code to choose more valueable choke points for
  16. ## watchtowers and a new unique improvement coming in 0.33.
  17. ##
  18. ## 1.05 - Cleaned up peak generation so that peaks on the map edge aren't
  19. ## always on desert. This prevents large amounts of flames slowing down the
  20. ## framerate. Added the 'scrubs' feature to map generation. Fixed a bug that
  21. ## prevented valleys from growing enough to find a neighbor.
  22. ##
  23. ## 1.04 - Added a tuning variable called SoftenPeakPercent which allows you to
  24. ## turn a percentage of peaks into hills to perforate the valleys and make
  25. ## them less like fortresses. Fixed a bug in detecting network games.
  26. ##
  27. ## 1.03 - Cleared forest and jungle from 1 tile around starting plot. This mod
  28. ## requires high tech levels to clear them and this can be a large hindrance.
  29. ## Civ preference with allowForestStart = True(Elves) will not clear the forest.
  30. ##
  31. ## 1.02 - Added a new civ placement scheme for FFH2 civs. Added a similar scheme
  32. ## for FFH2 unique improvements. Improved the way ancient towers are placed.
  33. ## Shrank the map yet again due the high percentage of playable land. Softened
  34. ## the effect of non-sea level land touching coast.
  35. ##
  36. ## 1.01 - Improved water area generation to more consistently make interesting
  37. ## map shapes. Water spread used to paint itself into a corner, this has been
  38. ## fixed. Prevented seas from being divided by small isthmuses. Only peaks and
  39. ## ocean will touch the map edge. Filled unreachable areas with peaks, we
  40. ## don't want Hyborem spawning there and you know he will if you let him.
  41. ## Shrank each map size, as there was too much room to expand for the default
  42. ## number of civs for each map size, resulting in no reason to go to war until
  43. ## late game. Temporarily added David Reichert's flavour map mod until I can
  44. ## do something with starting regions.
  45. #---
  46. # 1.07f Terkhen 12.Sep.2016
  47. # - changed, the map size is now proportional to the actual world sizes defined by the mod.
  48. # - changed, use grid definitions from the active mod instead of using hardcoded ones.
  49. # - fixed, correct reference to efJungle.
  50. # 1.07e Terkhen 17.Aug.2016
  51. # - fixed, use terrain, feature and improvement definitions from MST.
  52. # 1.07d Terkhen 08.Dic.2014
  53. # - added, save/load map options.
  54. # - added, allow to select between the map script starting point placer and the default one when using Fall from Heaven.
  55. # - added, compatibility with RandomMap.
  56. # - added, resource balance option.
  57. # - added, tubular wrapping.
  58. # - fixed, Erebus unique feature placer would not take into account changes to terrain made by MapScriptTools.
  59. # - fixed, use Erebus starting points only when using Fall from Heaven 2 based mods.
  60. # - fixed, prevention of assert errors.
  61. # - changed, use TXT strings instead of hardcoded ones.
  62. # - changed, the MapScript no longer needs to convert peaks from desert to tundra.
  63. # 1.07c Temudjin 15.Mar.2011
  64. # - fixed [Planetfall], compatibility to Planetfalls 'Scattered Pods' mod option
  65. # - fixed [Mars Now!], team start normalization
  66. # - added, new map option: expanded coastal waters (like Civ5)
  67. # - added [Mars Now!], new map option: 'Sands of Mars'/'Terraformed Mars'
  68. # - changed, stratified custom map option process
  69. # - changed, stratified normalization process
  70. # - changed [Mars Now!], using dedicated terrain generator
  71. # - add reefs if allowed by mod
  72. # 1.07b Temudjin 15.Jul.2010 - MapScriptTools
  73. # - compatibility with 'Planetfall'
  74. # - compatibility with 'Mars Now!'
  75. # - add Map Option: TeamStart
  76. # - add Marsh terrain, if supported by mod
  77. # - add Deep Ocean terrain, if supported by mod
  78. # - add some rivers on islands and from lakes
  79. # - allow more world sizes, if supported by mod
  80. # - add Map Regions ( BigDent, BigBog, ElementalQuarter, LostIsle )
  81. # - better bonus balancer
  82. # - print stats of mod and map
  83. # - add getVersion(), change getDescription()
  84. # 1.07a Opera
  85. # - add Map Features ( Kelp, HauntedLands, CrystalPlains ) - for Orbis
  86. #
  87. from CvPythonExtensions import *
  88. import CvUtil
  89. import CvMapGeneratorUtil
  90. from array import array
  91. from random import random,randint,seed
  92. import math
  93. import sys
  94. map = CyMap()
  95. ################################################################
  96. ## MapScriptTools Interface by Temudjin START
  97. ################################################################
  98. import MapScriptTools as mst
  99. balancer = mst.bonusBalancer
  100. def getVersion():
  101. return "1.07f_mst"
  102. def getDescription():
  103. return "TXT_KEY_MAP_SCRIPT_EREBUS_DESCR"
  104. # #################################################################################################
  105. # ######## randomMapBeforeInit() - Starts the map-generation process, called by RandomMap to set
  106. # ######## the map options
  107. # #################################################################################################
  108. def randomMapBeforeInit(moWorldShape, moResources, moCoastalWaters, moTeamStart, moMarsTheme):
  109. print "-- randomMapBeforeInit()"
  110. # Avoid errors while printing custom options.
  111. global op
  112. op = {}
  113. # Map options of this script
  114. global mapOptionWorldShape, mapOptionMountains, mapOptionStartingMethod
  115. global mapOptionCoastalWaters, mapOptionTeamStart, mapOptionMarsTheme, mapOptionResources
  116. # Options chosen in Random Map
  117. mapOptionWorldShape = moWorldShape
  118. mapOptionResources = moResources
  119. mapOptionCoastalWaters = moCoastalWaters
  120. mapOptionTeamStart = moTeamStart
  121. mapOptionMarsTheme = moMarsTheme
  122. # All other options are chosen randomly.
  123. # Give no softening a greater chance than other options.
  124. mapOptionMountains = CyGlobalContext().getGame().getMapRand().get(18, "Erebus.randomMapBeforeInit(), mapOptionMountains")
  125. if mapOptionMountains > 11:
  126. mapOptionMountains = 0
  127. if mst.bFFH:
  128. mapOptionStartingMethod = CyGlobalContext().getGame().getMapRand().get(2, "Erebus.randomMapBeforeInit(), mapOptionStartingMethod")
  129. else:
  130. mapOptionStartingMethod = 1
  131. # FF: Added by Jean Elcard 11/20/2008
  132. mc.initialize()
  133. mc.WrapX = (mapOptionWorldShape in [1, 3])
  134. mc.WrapY = (mapOptionWorldShape in [2, 3])
  135. mc.SoftenPeakPercent = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0][mapOptionMountains]
  136. # FF: End
  137. # #################################################################################################
  138. # ######## beforeInit() - Starts the map-generation process, called after the map-options are known
  139. # ######## - map dimensions, latitudes and wrapping status are not known yet
  140. # ######## - handle map specific options
  141. # #################################################################################################
  142. def beforeInit():
  143. print "-- beforeInit()"
  144. # Selected map options
  145. global mapOptionWorldShape, mapOptionMountains, mapOptionStartingMethod
  146. global mapOptionCoastalWaters, mapOptionTeamStart, mapOptionMarsTheme, mapOptionResources
  147. mapOptionWorldShape = map.getCustomMapOption(0)
  148. mapOptionResources = map.getCustomMapOption(1)
  149. mapOptionMountains = map.getCustomMapOption(2)
  150. if mst.bFFH:
  151. mapOptionStartingMethod = map.getCustomMapOption(3)
  152. else:
  153. mapOptionStartingMethod = 1
  154. mapOptionCoastalWaters = mst.iif(mst.bPfall, None, map.getCustomMapOption(4))
  155. mapOptionTeamStart = mst.iif(mst.bMars, None, map.getCustomMapOption( mst.iif(mst.bPfall,4,5) ))
  156. mapOptionMarsTheme = mst.iif(mst.bMars, map.getCustomMapOption(5), None)
  157. # FF: Added by Jean Elcard 11/20/2008
  158. mc.initialize()
  159. mc.WrapX = (mapOptionWorldShape in [1, 3])
  160. mc.WrapY = (mapOptionWorldShape in [2, 3])
  161. mc.SoftenPeakPercent = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0][mapOptionMountains]
  162. # FF: End
  163. def beforeGeneration():
  164. print "-- beforeGeneration()"
  165. # Create mapInfo string
  166. mapInfo = ""
  167. # Backup current language
  168. iLanguage = CyGame().getCurrentLanguage()
  169. # Force english language for logs
  170. CyGame().setCurrentLanguage(0)
  171. for opt in range( getNumCustomMapOptions() ):
  172. nam = getCustomMapOptionName( [opt] )
  173. sel = map.getCustomMapOption( opt )
  174. txt = getCustomMapOptionDescAt( [opt,sel] )
  175. mapInfo += "%27s: %s\n" % ( nam, txt )
  176. # Restore current language
  177. CyGame().setCurrentLanguage(iLanguage)
  178. # Obtain the map options in use.
  179. lMapOptions = []
  180. for opt in range( getNumCustomMapOptions() ):
  181. iValue = 0 + map.getCustomMapOption( opt )
  182. lMapOptions.append( iValue )
  183. # Save used map options.
  184. mst.mapOptionsStorage.writeConfig(lMapOptions)
  185. # Initialize MapScriptTools
  186. mst.getModInfo( getVersion(), None, mapInfo )
  187. # Determine global Mars Theme
  188. mst.bSandsOfMars = (mapOptionMarsTheme == 0)
  189. # Initialize bonus balancing
  190. balancer.initialize( mapOptionResources == 1 ) # balance boni if desired, place missing boni, move minerals
  191. def addRivers():
  192. print "-- addRivers()"
  193. mst.mapPrint.buildRiverMap( True, "addRivers()" )
  194. # Generate marsh-terrain
  195. mst.marshMaker.convertTerrain()
  196. # Expand coastal waters
  197. if mapOptionCoastalWaters == 1:
  198. mst.mapPrettifier.expandifyCoast()
  199. # Build between 0..2 mountain-ranges.
  200. mst.mapRegions.buildBigDents()
  201. # Build between 0..2 bog-regions.
  202. mst.mapRegions.buildBigBogs()
  203. # Generate DeepOcean-terrain if mod allows for it
  204. mst.deepOcean.buildDeepOcean()
  205. # No standard rivers on Mars
  206. if not mst.bMars:
  207. # Put rivers on the map.
  208. CyPythonMgr().allowDefaultImpl()
  209. # addRivers2() # can't use this; doesn't understand the mapRegions changes
  210. # Put rivers on small islands
  211. mst.riverMaker.islandRivers()
  212. def addLakes():
  213. print "-- addLakes()"
  214. return None
  215. def addFeatures():
  216. print "-- addFeatures()"
  217. mst.mapPrint.buildRiverMap( True, "addFeatures()" )
  218. # Kill of spurious lakes
  219. mst.mapPrettifier.connectifyLakes( 33 )
  220. # Sprout rivers from lakes.
  221. mst.riverMaker.buildRiversFromLake( None, 50, 2, 3 )
  222. if mst.bPfall or mst.bMars:
  223. # Planetfall / Mars Now! use default featureGenerator
  224. featuregen = mst.MST_FeatureGenerator()
  225. featuregen.addFeatures()
  226. else:
  227. # Use scripts featureGenerator
  228. addFeatures2() # call renamed script function
  229. # Prettify the map - transform coastal volcanos; default: 66% chance
  230. # mst.mapPrettifier.beautifyVolcanos()
  231. # Mars Now!: lumpify sandstorms
  232. if mst.bMars: mst.mapPrettifier.lumpifyTerrain( mst.efSandStorm, FeatureTypes.NO_FEATURE )
  233. # Planetfall: handle shelves and trenches
  234. if mst.bPfall: mst.planetFallMap.buildPfallOcean()
  235. # FFH: build ElementalQuarter; default: 5% chance
  236. mst.mapRegions.buildElementalQuarter()
  237. def afterGeneration():
  238. print "-- afterGeneration()"
  239. spf.initialize()
  240. if not mst.bFFH: return
  241. count = spf.collectAllWatchtowers()
  242. spf.replaceWatchtowers(count)
  243. spf.replaceUniqueImprovements()
  244. def assignStartingPlots():
  245. if mapOptionStartingMethod == 1: # Planetfall uses default (Temudjin)
  246. CyPythonMgr().allowDefaultImpl() # Flat World uses default (Jean Elcard 15/12/2008)
  247. else:
  248. spf.assignStartingPlots()
  249. def normalizeStartingPlotLocations():
  250. print "-- normalizeStartingPlotLocations()"
  251. mst.mapPrint.buildRiverMap( True, "normalizeStartingPlotLocations()" )
  252. # build Lost Isle
  253. # - this region needs to be placed after starting-plots are first assigned
  254. mst.mapRegions.buildLostIsle()
  255. if mst.bMars:
  256. # Mars Now! uses no teams
  257. CyPythonMgr().allowDefaultImpl()
  258. elif mapOptionTeamStart == 0:
  259. # by default civ places teams near to each other
  260. CyPythonMgr().allowDefaultImpl()
  261. elif mapOptionTeamStart == 1:
  262. # shuffle starting-plots to separate teams
  263. mst.teamStart.placeTeamsTogether( False, True )
  264. else:
  265. # randomize starting-plots to ignore teams
  266. mst.teamStart.placeTeamsTogether( True, True )
  267. # ############################################################################################
  268. # ######## normalizeAddRiver() - Called from system after normalizeStartingPlotLocations()
  269. # ######## - SECOND STAGE in 'Normalize Starting-Plots'
  270. # ######## - add some rivers if needed
  271. # ############################################################################################
  272. def normalizeAddRiver():
  273. print "-- normalizeAddRiver()"
  274. return None
  275. # ############################################################################################
  276. # ######## normalizeRemovePeaks() - Called from system after normalizeAddRiver()
  277. # ######## - THIRD STAGE in 'Normalize Starting-Plots'
  278. # ######## - remove some peaks if needed
  279. # ############################################################################################
  280. def normalizeRemovePeaks():
  281. print "-- normalizeRemovePeaks()"
  282. return None
  283. # ############################################################################################
  284. # ######## normalizeAddLakesRiver() - Called from system after normalizeRemovePeaks()
  285. # ######## - FOURTH STAGE in 'Normalize Starting-Plots'
  286. # ######## - add some lakes if needed
  287. # ############################################################################################
  288. def normalizeAddLakes():
  289. print "-- normalizeAddLakes()"
  290. return None
  291. # ############################################################################################
  292. # ######## normalizeRemoveBadFeatures() - Called from system after normalizeAddLakes()
  293. # ######## - FIFTH STAGE in 'Normalize Starting-Plots'
  294. # ######## - remove bad features if needed
  295. # ############################################################################################
  296. def normalizeRemoveBadFeatures():
  297. print "-- normalizeRemoveBadFeatures()"
  298. if mst.bFFH:
  299. gc = CyGlobalContext()
  300. gameMap = CyMap()
  301. civPrefList = GetCivPreferences()
  302. playerList = list()
  303. for playerIndex in range(gc.getMAX_CIV_PLAYERS()):
  304. player = gc.getPlayer(playerIndex)
  305. if player.isEverAlive():
  306. civType = player.getCivilizationType()
  307. civPref = spf.getCivPreference(civPrefList,civType)
  308. if civPref.allowForestStart == True:
  309. continue
  310. plot = player.getStartingPlot()
  311. featureType = plot.getFeatureType()
  312. if featureType == mst.efForest or \
  313. featureType == mst.efJungle:
  314. plot.setFeatureType(FeatureTypes.NO_FEATURE,0)
  315. for direction in range(1,9,1):
  316. xx,yy = plotMap.getXYFromDirection(plot.getX(),plot.getY(),direction)
  317. nPlot = gameMap.plot(xx,yy)
  318. featureType = nPlot.getFeatureType()
  319. if featureType == mst.efForest or \
  320. featureType == mst.efJungle:
  321. nPlot.setFeatureType(FeatureTypes.NO_FEATURE,0)
  322. return None
  323. # ############################################################################################
  324. # ######## normalizeRemoveBadTerrain() - Called from system after normalizeRemoveBadFeatures()
  325. # ######## - SIXTH STAGE in 'Normalize Starting-Plots'
  326. # ######## - change bad terrain if needed
  327. # ############################################################################################
  328. def normalizeRemoveBadTerrain():
  329. print "-- normalizeRemoveBadTerrain()"
  330. return None
  331. # ############################################################################################
  332. # ######## normalizeAddFoodBonuses() - Called from system after normalizeRemoveBadTerrain()
  333. # ######## - SEVENTH STAGE in 'Normalize Starting-Plots'
  334. # ######## - add food if needed
  335. # ############################################################################################
  336. def normalizeAddFoodBonuses():
  337. print "-- normalizeAddFoodBonuses()"
  338. if mst.bMars:
  339. CyPythonMgr().allowDefaultImpl()
  340. # ############################################################################################
  341. # ######## normalizeAddGoodTerrain() - Called from system after normalizeAddFoodBonuses()
  342. # ######## - EIGHTH STAGE in 'Normalize Starting-Plots'
  343. # ######## - add good terrain if needed
  344. # ############################################################################################
  345. def normalizeAddGoodTerrain():
  346. print "-- normalizeAddGoodTerrain()"
  347. return None
  348. def normalizeAddExtras():
  349. print "-- normalizeAddExtras()"
  350. # Balance boni, place missing boni, move minerals
  351. balancer.normalizeAddExtras()
  352. # Do the default housekeeping
  353. # CyPythonMgr().allowDefaultImpl()
  354. # Make sure marshes are on flatlands
  355. mst.marshMaker.normalizeMarshes()
  356. # Give extras to special regions
  357. mst.mapRegions.addRegionExtras()
  358. # Place special features on map
  359. mst.featurePlacer.placeFeatures()
  360. # Kill ice on warm edges. Erebus does not have extra ice when using toroidal wrapping.
  361. mst.mapPrettifier.deIcifyEdges(66, False)
  362. # Print plotMap and differencePlotMap
  363. mst.mapPrint.buildPlotMap( True, "normalizeAddExtras()" )
  364. # Print areaMap
  365. mst.mapPrint.buildAreaMap( True, "normalizeAddExtras()" )
  366. # Print terrainMap
  367. mst.mapPrint.buildTerrainMap( True, "normalizeAddExtras()" )
  368. # Print featureMap
  369. mst.mapPrint.buildFeatureMap( True, "normalizeAddExtras()" )
  370. # Print bonusMap
  371. mst.mapPrint.buildBonusMap( False, "normalizeAddExtras()" )
  372. # Print manaMap if FFH
  373. if mst.bFFH: mst.mapPrint.buildBonusMap( False, "normalizeAddExtras():Mana", None, mst.mapPrint.manaDict )
  374. # Print riverMap
  375. mst.mapPrint.buildRiverMap( True, "normalizeAddExtras()" )
  376. # Print mod and map statistics
  377. mst.mapStats.mapStatistics()
  378. def minStartingDistanceModifier():
  379. if mst.bPfall: return -25
  380. if mst.bMars: return -15
  381. return 0
  382. ################################################################
  383. ## Custom Map Option Interface by Temudjin START
  384. ################################################################
  385. def setCustomOptions():
  386. """ Set all custom options in one place """
  387. global op # { optionID: Name, OptionList, Default, RandomOpt }
  388. # Initialize options to the default values.
  389. lMapOptions = [0, 0, 0, 0, 0, 0]
  390. # Try to read map options from the cfgFile.
  391. mst.mapOptionsStorage.initialize(lMapOptions, 'Erebus')
  392. lMapOptions = mst.mapOptionsStorage.readConfig()
  393. optionMountains = [ "TXT_KEY_MAP_EREBUS_MOUNTAINS_NO_SOFTENING",
  394. "TXT_KEY_MAP_EREBUS_MOUNTAINS_10_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_20_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_30_PEAKS",
  395. "TXT_KEY_MAP_EREBUS_MOUNTAINS_40_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_50_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_60_PEAKS",
  396. "TXT_KEY_MAP_EREBUS_MOUNTAINS_70_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_80_PEAKS", "TXT_KEY_MAP_EREBUS_MOUNTAINS_90_PEAKS",
  397. "TXT_KEY_MAP_EREBUS_MOUNTAINS_NO_PEAKS" ]
  398. op = {
  399. 0: ["TXT_KEY_MAP_SCRIPT_WORLD_WRAP", ["TXT_KEY_MAP_SCRIPT_WORLD_WRAP_FLAT", "TXT_KEY_MAP_SCRIPT_WORLD_WRAP_CYLINDRICAL", "TXT_KEY_MAP_SCRIPT_WORLD_WRAP_TUBULAR", "TXT_KEY_MAP_SCRIPT_WORLD_WRAP_TOROIDAL"], lMapOptions[0], True],
  400. 1: ["TXT_KEY_MAP_RESOURCES", ["TXT_KEY_MAP_RESOURCES_STANDARD", "TXT_KEY_MAP_RESOURCES_BALANCED"], lMapOptions[1], True],
  401. 2: ["TXT_KEY_MAP_EREBUS_MOUNTAINS", optionMountains, lMapOptions[2], True],
  402. 3: ["TXT_KEY_MAP_EREBUS_STARTING_POSITIONS", ["TXT_KEY_MAP_EREBUS_STARTING_POSITIONS_EREBUS", "TXT_KEY_MAP_EREBUS_STARTING_POSITIONS_ORIGINAL"], lMapOptions[3], False],
  403. 4: ["TXT_KEY_MAP_COASTS", ["TXT_KEY_MAP_COASTS_STANDARD", "TXT_KEY_MAP_COASTS_EXPANDED"], lMapOptions[4], True],
  404. "Hidden": 4
  405. }
  406. if mst.bPfall:
  407. op[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]
  408. elif mst.bMars:
  409. op[5] = ["TXT_KEY_MAP_MARS_THEME", ["TXT_KEY_MAP_MARS_THEME_SANDS_OF_MARS", "TXT_KEY_MAP_MARS_THEME_TERRAFORMED_MARS"], lMapOptions[5], False]
  410. else:
  411. op[5] = ["TXT_KEY_MAP_TEAM_START", ["TXT_KEY_MAP_TEAM_START_NEIGHBORS", "TXT_KEY_MAP_TEAM_START_SEPARATED", "TXT_KEY_MAP_TEAM_START_RANDOM"], lMapOptions[5], False]
  412. if not mst.bFFH:
  413. op[3] = ["TXT_KEY_MAP_EREBUS_STARTING_POSITIONS", ["TXT_KEY_MAP_EREBUS_STARTING_POSITIONS_ORIGINAL"], lMapOptions[3], False]
  414. mst.printDict(op,"Erebus Map Options:")
  415. def isAdvancedMap():
  416. """ This map should show up in simple mode """
  417. return 0
  418. # first function to be called by the map building process
  419. def getNumHiddenCustomMapOptions():
  420. """ Default is used for the last n custom-options in 'Play Now' mode. """
  421. setCustomOptions() # Define Options
  422. return op["Hidden"]
  423. def getNumCustomMapOptions():
  424. """ Number of different user-defined options for this map """
  425. return len( op ) - 1
  426. def getCustomMapOptionName(argsList):
  427. """ Returns name of specified option """
  428. optionID = argsList[0]
  429. translated_text = unicode(CyTranslator().getText(op[optionID][0], ()))
  430. return translated_text
  431. def getNumCustomMapOptionValues(argsList):
  432. """ Number of different choices for a particular setting """
  433. optionID = argsList[0]
  434. return len( op[optionID][1] )
  435. def getCustomMapOptionDescAt(argsList):
  436. """ Returns name of value of option at specified row """
  437. optionID = argsList[0]
  438. valueID = argsList[1]
  439. translated_text = unicode(CyTranslator().getText(op[optionID][1][valueID], ()))
  440. return translated_text
  441. def getCustomMapOptionDefault(argsList):
  442. """ Returns default value of specified option """
  443. optionID = argsList[0]
  444. return op[optionID][2]
  445. def isRandomCustomMapOption(argsList):
  446. """ Returns a flag indicating whether a random option should be provided """
  447. optionID = argsList[0]
  448. return op[optionID][3]
  449. ################################################################
  450. ## Interfaces by Temudjin END
  451. ################################################################
  452. def isClimateMap():
  453. """ Uses the Climate options """
  454. return True
  455. def isSeaLevelMap():
  456. """ Uses the Sea Level options """
  457. return True
  458. def getTopLatitude():
  459. """ Default is 90. 75 is past the Arctic Circle """
  460. return 90
  461. def getBottomLatitude():
  462. """ Default is -90. -75 is past the Antartic Circle """
  463. return -90
  464. def getWrapX():
  465. return mc.WrapX
  466. def getWrapY():
  467. return mc.WrapY
  468. def isBonusIgnoreLatitude():
  469. return True
  470. ##########
  471. def getGridSize(argsList):
  472. """ Adjust grid sizes for optimum results """
  473. if argsList[0] == -1: return [] # (-1,) is passed to function on loads
  474. # FF: Changed by Jean Elcard 11/22/2008 (moved to beforeInit())
  475. '''
  476. mc.initialize()
  477. '''
  478. # FF: End Change
  479. seaLevel = CyMap().getSeaLevel()
  480. scaler = 1.0
  481. if seaLevel == GetInfoType("SEALEVEL_LOW"):
  482. scaler = math.sqrt((mc.RegionsPerPlot - mc.WaterRegionsPerPlot)/(mc.RegionsPerPlot - mc.WaterRegionsPerPlot * 0.5))
  483. mc.WaterRegionsPerPlot = mc.WaterRegionsPerPlot * 0.5
  484. print "Sea level is low, map dimension scaler = %f" % scaler
  485. elif seaLevel == GetInfoType("SEALEVEL_HIGH"):
  486. scaler = math.sqrt((mc.RegionsPerPlot - mc.WaterRegionsPerPlot)/(mc.RegionsPerPlot - mc.WaterRegionsPerPlot * 3.0))
  487. mc.WaterRegionsPerPlot = mc.WaterRegionsPerPlot * 2.0
  488. print "Sea level is high, map dimension scaler = %f" % scaler
  489. # MST changed: The map size is now proportional to the actual world sizes defined by the mod.
  490. # Duel and tiny maps are slightly smaller than before, while huge maps are slightly larger.
  491. [eWorldSize] = argsList
  492. iMapSize = int(scaler * CyGlobalContext().getWorldInfo(eWorldSize).getGridHeight())
  493. return iMapSize, iMapSize
  494. ##########
  495. class MapConstants :
  496. def __init__(self):
  497. return
  498. def initialize(self):
  499. ##############################################################################
  500. # Tunable variables
  501. ##############################################################################
  502. #Decides whether to use the Python random generator or the one that is
  503. #intended for use with civ maps. The Python random has much higher precision
  504. #than the civ one. 53 bits for Python result versus 16 for getMapRand. The
  505. #rand they use is actually 32 bits, but they shorten the result to 16 bits.
  506. #However, the problem with using the Python random is that it may create
  507. #syncing issues for multi-player now or in the future, therefore it must
  508. #be optional.
  509. self.UsePythonRandom = True
  510. #This variable turns on things that only make sense with Fall from Heaven 2
  511. self.FFHSpecific = mst.bFFH # was True
  512. #This variable will make a percentage of peaks into hills in order to break
  513. #up the worlds valleys. I set this to zero because I feel it diminishes the
  514. #illusion of differing climates between valleys and looks bad.
  515. self.SoftenPeakPercent = 0.0
  516. #This variable decides how many tiles of drainage is needed to create a
  517. #river.
  518. self.RiverThreshold = 5.0
  519. #The amount of rainfall in the dryest desert. Must be between 1.0 and 0.0
  520. self.MinRainfall = .25
  521. #This number is multiplied by the RiverThreshold to determine when a river
  522. #is large enough to have a 100% chance to flatten nearby hills and peaks.
  523. self.RiverFactorFlattensAll = 10.0
  524. self.RiverAddsMoistureRange = .20
  525. self.RiverAddsMoistureMax = 10.0
  526. #These variables control the frequency of hills and peaks at the lowest
  527. #and highest altitudes
  528. self.HillChanceAtZero = .15
  529. self.HillChanceAtOne = .90
  530. self.PeakChanceAtZero = .0
  531. self.PeakChanceAtOne = .20
  532. #These valiables control the moisture thresholds for desert and plains
  533. self.JungleThreshold = .90
  534. self.PlainsThreshold = .50
  535. self.DesertThreshold = .30
  536. #Chance for jungle to have marsh, and chance for marsh to replace jungle
  537. self.ChanceForMarsh = 0.30
  538. self.ChanceForOnlyMarsh = 0.33
  539. #These variables control the altitude of tundra and ice. Also, in Civ,
  540. #deserts are supposed to be hot, so we'll limit the altitude for deserts
  541. self.TundraThreshold = .74
  542. self.IceThreshold = .84
  543. self.MaxDesertAltitude = .65
  544. #The type of trees are controlled by altitude. Snowy trees use TundraThreshold.
  545. #Lower than leafy is Jungle.
  546. self.LeafyAltitude = .30
  547. self.EvergreenAltitude = .60
  548. #Chance for an oasis to appear in desert
  549. self.OasisChance = .08
  550. #Map constants - I'm making a point on this map to hardcode nothing, so some
  551. #of these may seem a bit obscure.
  552. #-------------------------------------------------------------------
  553. self.RegionsPerPlot = 0.009 #Map regions(valleys, seas) per map plot
  554. self.WaterRegionsPerPlot = 0.002 #Water regions per map plot
  555. self.MinSeedRange = 5 #Closest that a region seed can be placed to another
  556. self.MinEdgeRange = 5 #Closest that a region seed can be to map edge
  557. self.ChanceToGrow = 0.25 #Base chance for each tile in region to grow
  558. self.EdgeLimit = 2 #Region stops growing this far from edge
  559. self.RiverAltitudeSubtraction = 2.0 #Amount subtracted from a plots altitude depending on river size
  560. self.RiverAltRangeFactor = 2.0 #Amount of RiverThreshold to use for altitude calc
  561. self.MinRegionSizeStart = 40 #Minimum region size for a starting plot
  562. self.MinRegionSizeTower = 30 #Minimum region size for a tower placement
  563. self.ChokePointAreaSize = 10 #chokepoint needs this size area on both sides
  564. self.ChokePointWalkAroundDistance = 12 #chokepoint must cause this much extra walking to be considered a choke
  565. self.WrapX = False # Dont touch these, this map has no wrap # Huh?
  566. self.WrapY = False
  567. return
  568. mc = MapConstants()
  569. def GetCivPreferences():
  570. ## Civs without preferences will use default values.
  571. ##
  572. ## Civ Name from XML
  573. ## pref = CivPreference(GetInfoType("CIVILIZATION_MALAKIM"))
  574. ##
  575. ## Self explanatory.
  576. ## pref.idealMoisture = 0.1
  577. ## pref.idealAltitude = 0.25
  578. ##
  579. ## These weights influence the effect of each preference. moistureWeight
  580. ## is hard coded as 1.0 for civ placement
  581. ## pref.altitudeWeight = 0.25
  582. ## pref.distanceWeight = 0.25 #how hard to try to start away from other civs
  583. ## pref.needCoastalStart = False
  584. civPreferenceList = list()
  585. pref = CivPreference(GetInfoType("CIVILIZATION_MALAKIM"))
  586. pref.idealMoisture = 0.1
  587. pref.idealAltitude = 0.25
  588. pref.altitudeWeight = 0.25
  589. pref.distanceWeight = 0.25
  590. pref.needCoastalStart = False
  591. pref.allowForestStart = False
  592. civPreferenceList.append(pref)
  593. pref = CivPreference(GetInfoType("CIVILIZATION_DOVIELLO"))
  594. pref.idealMoisture = 0.8
  595. pref.idealAltitude = 0.95
  596. pref.altitudeWeight = 2.0
  597. pref.distanceWeight = 0.75
  598. pref.needCoastalStart = False
  599. pref.allowForestStart = False
  600. civPreferenceList.append(pref)
  601. pref = CivPreference(GetInfoType("CIVILIZATION_ILLIANS"))
  602. pref.idealMoisture = 0.5
  603. pref.idealAltitude = 0.95
  604. pref.altitudeWeight = 2.0
  605. pref.distanceWeight = 0.75
  606. pref.needCoastalStart = False
  607. pref.allowForestStart = False
  608. civPreferenceList.append(pref)
  609. pref = CivPreference(GetInfoType("CIVILIZATION_KHAZAD"))
  610. pref.idealMoisture = 0.35
  611. pref.idealAltitude = 0.75
  612. pref.altitudeWeight = 2.0
  613. pref.distanceWeight = 0.75
  614. pref.needCoastalStart = False
  615. pref.allowForestStart = False
  616. civPreferenceList.append(pref)
  617. pref = CivPreference(GetInfoType("CIVILIZATION_LUCHUIRP"))
  618. pref.idealMoisture = 0.35
  619. pref.idealAltitude = 0.75
  620. pref.altitudeWeight = 2.0
  621. pref.distanceWeight = 0.75
  622. pref.needCoastalStart = False
  623. pref.allowForestStart = False
  624. civPreferenceList.append(pref)
  625. pref = CivPreference(GetInfoType("CIVILIZATION_LJOSALFAR"))
  626. pref.idealMoisture = 0.75
  627. pref.idealAltitude = 0.23
  628. pref.altitudeWeight = 2.0
  629. pref.distanceWeight = 0.25
  630. pref.needCoastalStart = False
  631. pref.allowForestStart = True
  632. civPreferenceList.append(pref)
  633. pref = CivPreference(GetInfoType("CIVILIZATION_LANUN"))
  634. pref.idealMoisture = 0.5
  635. pref.idealAltitude = 0.0
  636. pref.altitudeWeight = 2.0
  637. pref.distanceWeight = 0.25
  638. pref.needCoastalStart = True
  639. pref.allowForestStart = False
  640. civPreferenceList.append(pref)
  641. pref = CivPreference(GetInfoType("CIVILIZATION_HIPPUS"))
  642. pref.idealMoisture = 0.4
  643. pref.idealAltitude = 0.1
  644. pref.altitudeWeight = 0.5
  645. pref.distanceWeight = 0.25
  646. pref.needCoastalStart = False
  647. pref.allowForestStart = False
  648. civPreferenceList.append(pref)
  649. pref = CivPreference(GetInfoType("CIVILIZATION_SVARTALFAR"))
  650. pref.idealMoisture = 0.7
  651. pref.idealAltitude = 0.35
  652. pref.altitudeWeight = 1.0
  653. pref.distanceWeight = 2.0
  654. pref.needCoastalStart = False
  655. pref.allowForestStart = True
  656. civPreferenceList.append(pref)
  657. return civPreferenceList
  658. def GetImprovementPreferences():
  659. #These values are similar to the way civs work except distanceWeight is
  660. #hardcoded as 1.0
  661. impPreferenceList = list()
  662. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_GUARDIAN"))
  663. pref.idealMoisture = .6
  664. pref.idealAltitude = .8
  665. pref.moistureWeight = .5
  666. pref.altitudeWeight = 1.0
  667. pref.needCoast = False
  668. pref.needWater = False
  669. pref.needHill = False
  670. pref.needFlat = False
  671. pref.needChoke = True #Only for guardian at this time
  672. impPreferenceList.append(pref)
  673. ## Removed to prevent 2 brigits from appearing upon moving improvement
  674. ## pref = ImprovementPreference(GetInfoType("IMPROVEMENT_RING_OF_CARCER"))
  675. ## pref.idealMoisture = .6
  676. ## pref.idealAltitude = 1.0
  677. ## pref.moistureWeight = .25
  678. ## pref.altitudeWeight = 3.0
  679. ## pref.needCoast = False
  680. ## pref.needWater = False
  681. ## pref.needHill = True
  682. ## pref.needFlat = False
  683. ## pref.favoredTerrain = mst.etSnow
  684. ## impPreferenceList.append(pref)
  685. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_SEVEN_PINES"))
  686. pref.idealMoisture = .60
  687. pref.idealAltitude = .6
  688. pref.moistureWeight = 1.0
  689. pref.altitudeWeight = .5
  690. pref.needCoast = False
  691. pref.needWater = False
  692. pref.needHill = False
  693. pref.needFlat = False
  694. pref.favoredTerrain = mst.etGrass
  695. impPreferenceList.append(pref)
  696. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_STANDING_STONES"))
  697. pref.idealMoisture = .75
  698. pref.idealAltitude = .5
  699. pref.moistureWeight = 1.0
  700. pref.altitudeWeight = .5
  701. pref.needCoast = False
  702. pref.needWater = False
  703. pref.needHill = False
  704. pref.needFlat = True
  705. pref.favoredTerrain = mst.etGrass
  706. impPreferenceList.append(pref)
  707. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_BROKEN_SEPULCHER"))
  708. pref.idealMoisture = .6
  709. pref.idealAltitude = .5
  710. pref.moistureWeight = .5
  711. pref.altitudeWeight = .5
  712. pref.needCoast = False
  713. pref.needWater = False
  714. pref.needHill = False
  715. pref.needFlat = True
  716. impPreferenceList.append(pref)
  717. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_MIRROR_OF_HEAVEN"))
  718. pref.idealMoisture = .0
  719. pref.idealAltitude = .0
  720. pref.moistureWeight = 2.0
  721. pref.altitudeWeight = .25
  722. pref.needCoast = False
  723. pref.needWater = False
  724. pref.needHill = False
  725. pref.needFlat = False
  726. pref.favoredTerrain = mst.etDesert
  727. impPreferenceList.append(pref)
  728. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_DRAGON_BONES"))
  729. pref.idealMoisture = .35
  730. pref.idealAltitude = .35
  731. pref.moistureWeight = 1.0
  732. pref.altitudeWeight = 1.0
  733. pref.needCoast = False
  734. pref.needWater = False
  735. pref.needHill = False
  736. pref.needFlat = True
  737. impPreferenceList.append(pref)
  738. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_LETUM_FRIGUS"))
  739. pref.idealMoisture = .7
  740. pref.idealAltitude = 1.0
  741. pref.moistureWeight = .5
  742. pref.altitudeWeight = 2.0
  743. pref.needCoast = False
  744. pref.needWater = False
  745. pref.needHill = False
  746. pref.needFlat = True
  747. pref.favoredTerrain = mst.etSnow
  748. impPreferenceList.append(pref)
  749. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_ODIOS_PRISON"))
  750. pref.idealMoisture = .35
  751. pref.idealAltitude = .75
  752. pref.moistureWeight = 1.0
  753. pref.altitudeWeight = 2.0
  754. pref.needCoast = False
  755. pref.needWater = False
  756. pref.needHill = False
  757. pref.needFlat = True
  758. impPreferenceList.append(pref)
  759. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_POOL_OF_TEARS"))
  760. pref.idealMoisture = .5
  761. pref.idealAltitude = .5
  762. pref.moistureWeight = 1.0
  763. pref.altitudeWeight = 1.0
  764. pref.needCoast = False
  765. pref.needWater = False
  766. pref.needHill = False
  767. pref.needFlat = True
  768. impPreferenceList.append(pref)
  769. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_PYRE_OF_THE_SERAPHIC"))
  770. pref.idealMoisture = 1.0
  771. pref.idealAltitude = 0.0
  772. pref.moistureWeight = 2.0
  773. pref.altitudeWeight = .5
  774. pref.needCoast = False
  775. pref.needWater = False
  776. pref.needHill = False
  777. pref.needFlat = True
  778. impPreferenceList.append(pref)
  779. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_REMNANTS_OF_PATRIA"))
  780. pref.idealMoisture = .6
  781. pref.idealAltitude = .5
  782. pref.moistureWeight = .5
  783. pref.altitudeWeight = .5
  784. pref.needCoast = False
  785. pref.needWater = False
  786. pref.needHill = False
  787. pref.needFlat = True #Forest hill gives 9 hammers which is OP imo.
  788. impPreferenceList.append(pref)
  789. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_TOMB_OF_SUCELLUS"))
  790. pref.idealMoisture = .6
  791. pref.idealAltitude = .5
  792. pref.moistureWeight = 1.0
  793. pref.altitudeWeight = .5
  794. pref.needCoast = False
  795. pref.needWater = False
  796. pref.needHill = False
  797. pref.needFlat = True
  798. impPreferenceList.append(pref)
  799. pref = ImprovementPreference(GetInfoType("IMPROVEMENT_YGGDRASIL"))
  800. pref.idealMoisture = .75
  801. pref.idealAltitude = .25
  802. pref.moistureWeight = 2.0
  803. pref.altitudeWeight = 1.0
  804. pref.needCoast = False
  805. pref.needWater = False
  806. pref.needHill = False
  807. pref.needFlat = False
  808. pref.favoredTerrain = mst.etGrass
  809. impPreferenceList.append(pref)
  810. return impPreferenceList
  811. class ImprovementPreference :
  812. def __init__(self,improvement):
  813. self.improvement = improvement
  814. self.idealAltitude = .5
  815. self.idealMoisture = .6
  816. self.altitudeWeight = 1.0
  817. self.moistureWeight = 1.0
  818. self.needCoast = False
  819. self.needWater = False
  820. self.needHill = False
  821. self.needFlat = False
  822. self.needChoke = False
  823. self.favoredTerrain = TerrainTypes.NO_TERRAIN
  824. class CivPreference :
  825. def __init__(self,civ):
  826. self.civ = civ
  827. self.idealAltitude = 0.35
  828. self.idealMoisture = 0.7
  829. self.needCoastalStart = False
  830. self.allowForestStart = False
  831. self.altitudeWeight = 1.0
  832. self.distanceWeight = 2.0 #distance is most important for generic civs
  833. return
  834. class PythonRandom :
  835. def __init__(self):
  836. return
  837. def seed(self):
  838. #Python randoms are not usable in network games.
  839. if mc.UsePythonRandom:
  840. self.usePR = True
  841. else:
  842. self.usePR = False
  843. if self.usePR and CyGame().isNetworkMultiPlayer():
  844. print "Detecting network game. Setting UsePythonRandom to False."
  845. self.usePR = False
  846. if self.usePR:
  847. # Python 'long' has unlimited precision, while the random generator
  848. # has 53 bits of precision, so I'm using a 53 bit integer to seed the map!
  849. seed() #Start with system time
  850. seedValue = randint(0,9007199254740991)
  851. seed(seedValue)
  852. print "Random seed (Using Python rands) for this map is %(s)20d" % {"s":seedValue}
  853. ## seedValue = 5018808826709881
  854. ## seed(seedValue)
  855. ## print "Pre-set seed (Using Pyhon rands) for this map is %(s)20d" % {"s":seedValue}
  856. else:
  857. gc = CyGlobalContext()
  858. self.mapRand = gc.getGame().getMapRand()
  859. seedValue = self.mapRand.get(65535,"Seeding mapRand - PerfectWorld.py")
  860. self.mapRand.init(seedValue)
  861. print "Random seed (Using getMapRand) for this map is %(s)20d" % {"s":seedValue}
  862. ## seedValue = 56870
  863. ## self.mapRand.init(seedValue)
  864. ## print "Pre-set seed (Using getMapRand) for this map is %(s)20d" % {"s":seedValue}
  865. return
  866. def random(self):
  867. if self.usePR:
  868. return random()
  869. else:
  870. #This formula is identical to the getFloat function in CvRandom. It
  871. #is not exposed to Python so I have to recreate it.
  872. fResult = float(self.mapRand.get(65535,"Getting float -PerfectWorld.py"))/float(65535)
  873. # print fResult
  874. return fResult
  875. def randint(self,rMin,rMax):
  876. #if rMin and rMax are the same, then return the only option
  877. if rMin == rMax:
  878. return rMin
  879. #returns a number between rMin and rMax inclusive
  880. if self.usePR:
  881. return randint(rMin,rMax)
  882. else:
  883. #mapRand.get() is not inclusive, so we must make it so
  884. return rMin + self.mapRand.get(rMax + 1 - rMin,"Getting a randint - PerfectWorld.py")
  885. #Set up random number system for global access
  886. PRand = PythonRandom()
  887. #This function converts x and y to an index. Useful in case of future wrapping.
  888. def GetIndex(x,y):
  889. #Check X for wrap
  890. if mc.WrapX == True:
  891. xx = x % mapSize.MapWidth
  892. elif x < 0 or x >= mapSize.MapWidth:
  893. return -1
  894. else:
  895. xx = x
  896. #Check y for wrap
  897. if mc.WrapY == True:
  898. yy = y % mapSize.MapHeight
  899. elif y < 0 or y >= mapSize.MapHeight:
  900. return -1
  901. else:
  902. yy = y
  903. i = yy * mapSize.MapWidth + xx
  904. return i
  905. #This function converts x and y to an index on river crossing maps.
  906. def GetRxIndex(x,y):
  907. #Check X for wrap
  908. if mc.WrapX == True:
  909. xx = x % (mapSize.MapWidth + 1)
  910. elif x < 0 or x >= (mapSize.MapWidth + 1):
  911. return -1
  912. else:
  913. xx = x
  914. #Check y for wrap
  915. if mc.WrapY == True:
  916. yy = y % (mapSize.MapHeight + 1)
  917. elif y < 0 or y >= (mapSize.MapHeight + 1):
  918. return -1
  919. else:
  920. yy = y
  921. i = yy * (mapSize.MapWidth + 1) + xx
  922. return i
  923. class MapSize :
  924. def __init__(self):
  925. self.MapWidth = 0
  926. self.MapHeight = 0
  927. mapSize = MapSize()
  928. class RegionMap :
  929. def __init__(self):
  930. return
  931. def createRegions(self):
  932. #Growing the regions directly according to the map size created
  933. #unsolvable problems for the river system. Instead, I am growing
  934. #on a map (regionRxMap) that corresponds to rivers rather than
  935. #map tiles. This ensures rivers have a path from region to
  936. #region.
  937. self.L = 0
  938. self.N = 1
  939. self.S = 2
  940. self.E = 3
  941. self.W = 4
  942. self.NE = 5
  943. self.NW = 6
  944. self.SE = 7
  945. self.SW = 8
  946. self.highestRegionAltitude = 0
  947. numTiles = mapSize.MapWidth*mapSize.MapHeight
  948. numRx = (mapSize.MapWidth + 1)*(mapSize.MapHeight + 1)
  949. print "MapWidth = %(mw)d,MapHeight = %(mh)d" % {"mw":mapSize.MapWidth,"mh":mapSize.MapHeight}
  950. self.regionMap = array('i')
  951. self.regionRxMap = array('i')
  952. self.regionList = list()
  953. self.regionPlotList = list()
  954. #initialize map
  955. #The value for unplayable areas will remain -1. playable regions
  956. #will stop growing when they touch a map edge.
  957. for i in range(numTiles):
  958. self.regionMap.append(-1)
  959. for i in range(numRx):
  960. self.regionRxMap.append(-1)
  961. numRegions = int(float(numTiles) * mc.RegionsPerPlot)
  962. print "numTiles = %(n)d, numRegions = %(w)d" % {"n":numTiles,"w":numRegions}
  963. for i in range(numRegions):
  964. #first find a random seed point that is not blocked by
  965. #previous points
  966. iterations = 0
  967. while(True):
  968. iterations += 1
  969. if iterations > 10000:
  970. raise ValueError, "endless loop in region seed placement"
  971. seedX = PRand.randint(0,mapSize.MapWidth + 1)
  972. seedY = PRand.randint(0,mapSize.MapHeight + 1)
  973. if self.isSeedBlocked(seedX,seedY) == False:
  974. region = Region(i,seedX,seedY)
  975. self.regionList.append(region)
  976. n = GetRxIndex(seedX,seedY)
  977. self.regionRxMap[n] = i
  978. plot = RegionPlot(i,seedX,seedY)
  979. self.regionPlotList.append(plot)
  980. #Now fill a 3x3 area to insure a minimum region size
  981. for direction in range(1,9,1):
  982. xx,yy = self.getXYFromDirection(seedX,seedY,direction)
  983. nn = GetRxIndex(xx,yy)
  984. self.regionRxMap[nn] = i
  985. plot = RegionPlot(i,xx,yy)
  986. self.regionPlotList.append(plot)
  987. break
  988. ## self.PrintRegionRxMap(False)
  989. #Now cause the seeds to grow into regions
  990. iterations = 0
  991. while(len(self.regionPlotList) > 0):
  992. iterations += 1
  993. if iterations > 200000:
  994. self.PrintRegionRxMap(False)
  995. raise ValueError, "endless loop in region growth"
  996. plot = self.regionPlotList[0]
  997. region = self.getRegionByID(plot.regionID)
  998. if region.isGrowing == False:
  999. del self.regionPlotList[0]
  1000. continue
  1001. roomLeft = False
  1002. for direction in range(1,5,1):
  1003. xx,yy = self.getXYFromDirection(plot.x,plot.y,direction)
  1004. i = GetRxIndex(xx,yy)
  1005. if i == -1 or self.rxTouchesMapEdge(xx,yy):
  1006. if self.canRegionGrowHere(xx,yy,plot.regionID):
  1007. self.regionRxMap[i] = plot.regionID
  1008. newPlot = RegionPlot(plot.regionID,xx,yy)
  1009. self.regionPlotList.append(newPlot)
  1010. if region.isTouchingNeighbor:
  1011. region.isGrowing = False
  1012. continue
  1013. if self.canRegionGrowHere(xx,yy,plot.regionID):
  1014. roomLeft = True
  1015. if PRand.random() < mc.ChanceToGrow:
  1016. self.regionRxMap[i] = plot.regionID
  1017. newPlot = RegionPlot(plot.regionID,xx,yy)
  1018. self.regionPlotList.append(newPlot)
  1019. #move plot to the end of the list if room left, otherwise
  1020. #delete it if no room left
  1021. if roomLeft:
  1022. self.regionPlotList.append(plot)
  1023. del self.regionPlotList[0]
  1024. ## self.PrintRegionRxMap(False)
  1025. #Now convert regionRxMap to regionMap
  1026. for y in range(mapSize.MapHeight + 1):
  1027. for x in range(mapSize.MapWidth + 1):
  1028. i = GetRxIndex(x,y)
  1029. regionID = self.regionRxMap[i]
  1030. if regionID != -1:
  1031. region = self.getRegionByID(regionID)
  1032. for direction in range(5,9,1):
  1033. xx,yy = self.plotFromRx(x,y,direction)
  1034. if xx == 71 and yy == 71:
  1035. print "x=%d,y=%d,xx=%d,yy=%d" % (x,y,xx,yy)
  1036. ii = GetIndex(xx,yy)
  1037. if ii != -1:
  1038. self.regionMap[ii] = regionID
  1039. newPlot = RegionPlot(regionID,xx,yy)
  1040. region.plotList.append(newPlot)
  1041. #Mark border tiles and neighbor regions
  1042. for region in self.regionList:
  1043. for plot in region.plotList:
  1044. i = GetIndex(plot.x,plot.y)
  1045. for direction in range(1,5,1):
  1046. if direction == 1:#N
  1047. xx = plot.x
  1048. yy = plot.y + 1
  1049. elif direction == 2:#S
  1050. xx = plot.x
  1051. yy = plot.y - 1
  1052. elif direction == 3:#E
  1053. xx = plot.x + 1
  1054. yy = plot.y
  1055. else:#W
  1056. xx = plot.x - 1
  1057. yy = plot.y
  1058. ii = GetIndex(xx,yy)
  1059. if ii != -1 and self.regionMap[ii] != -1 and \
  1060. self.regionMap[ii] != region.ID:
  1061. plot.bBorder = True
  1062. plot.bEdge = True
  1063. AppendUnique(region.neighborList,self.regionMap[ii])
  1064. elif self.regionMap[ii] == -1:
  1065. plot.bEdge = True
  1066. ## self.PrintRegionMap(False)
  1067. #Now choose areas to be water
  1068. numWaterRegions = int(float(numTiles) * mc.WaterRegionsPerPlot)
  1069. print "numTiles = %(n)d, numWaterRegions = %(w)d" % {"n":numTiles,"w":numWaterRegions}
  1070. self.regionList = ShuffleList(self.regionList)
  1071. #Try to start with the region in the middle (there is a low chance that there isn't one)
  1072. i = GetIndex(mapSize.MapWidth/2, mapSize.MapHeight/2)
  1073. regionID = self.regionMap[i]
  1074. if regionID == -1:
  1075. self.regionList[0].isWater = True
  1076. else:
  1077. region = self.getRegionByID(regionID)
  1078. region.isWater = True
  1079. for i in range(numWaterRegions):
  1080. self.regionList = ShuffleList(self.regionList)
  1081. for nRegion in self.regionList:
  1082. nRegion.waterNeighborCount = nRegion.getWaterNeighborCount()
  1083. self.regionList.sort(lambda x,y:cmp(x.waterNeighborCount,y.waterNeighborCount))
  1084. for nRegion in self.regionList:
  1085. if nRegion.waterNeighborCount > 0 and nRegion.isWater == False:
  1086. nRegion.isWater = True
  1087. break
  1088. ## self.PrintRegionMap(False)
  1089. #Now fill any non-areas adjacent to water with the water area
  1090. for region in self.regionList:
  1091. if region.isWater == False:
  1092. continue
  1093. regionExpanding = True
  1094. while(regionExpanding):
  1095. regionExpanding = region.expandWaterRegion()
  1096. ## self.PrintRegionMap(False)
  1097. return
  1098. def canRegionGrowHere(self,x,y,regionID):
  1099. i = GetRxIndex(x,y)
  1100. if i == -1:
  1101. return False
  1102. if self.regionRxMap[i] != -1:
  1103. return False
  1104. region = self.getRegionByID(regionID)
  1105. if not region.isGrowing:
  1106. return False
  1107. assume = True
  1108. for direction in range(1,9,1):
  1109. xx,yy = self.getXYFromDirection(x,y,direction)
  1110. ii = GetRxIndex(xx,yy)
  1111. if ii == -1 or self.regionRxMap[ii] == regionID:
  1112. continue
  1113. elif self.regionRxMap[ii] == -1:
  1114. continue
  1115. else:#region is touching a neighbor
  1116. region.isTouchingNeighbor = True
  1117. assume = False
  1118. return assume
  1119. def rxTouchesMapEdge(self,x,y):
  1120. if x >= (mapSize.MapWidth + 1) - mc.EdgeLimit or x < mc.EdgeLimit:
  1121. return True
  1122. if y >= (mapSize.MapHeight + 1) - mc.EdgeLimit or y < mc.EdgeLimit:
  1123. return True
  1124. return False
  1125. def plotFromRx(self,rxX,rxY,direction):
  1126. if direction == self.NE:
  1127. x = rxX
  1128. y = rxY
  1129. elif direction == self.NW:
  1130. x = rxX - 1
  1131. y = rxY
  1132. elif direction == self.SE:
  1133. x = rxX
  1134. y = rxY - 1
  1135. else:#SW
  1136. x = rxX - 1
  1137. y = rxY - 1
  1138. #check for validity
  1139. if x < 0 or x >= mapSize.MapWidth:
  1140. return -1,-1
  1141. if y < 0 or y >= mapSize.MapHeight:
  1142. return -1,-1
  1143. return x,y
  1144. def getXYFromDirection(self,x,y,direction):
  1145. xx = x
  1146. yy = y
  1147. if direction == self.N:
  1148. yy += 1
  1149. elif direction == self.S:
  1150. yy -= 1
  1151. elif direction == self.E:
  1152. xx += 1
  1153. elif direction == self.W:
  1154. xx -= 1
  1155. elif direction == self.NW:
  1156. yy += 1
  1157. xx -= 1
  1158. elif direction == self.NE:
  1159. yy += 1
  1160. xx += 1
  1161. elif direction == self.SW:
  1162. yy -= 1
  1163. xx -= 1
  1164. elif direction == self.SE:
  1165. yy -= 1
  1166. xx += 1
  1167. return xx,yy
  1168. def isSeedBlocked(self,seedX,seedY):
  1169. for region in self.regionList:
  1170. if seedX > region.seedX - mc.MinSeedRange and seedX < region.seedX + mc.MinSeedRange:
  1171. if seedY > region.seedY - mc.MinSeedRange and seedY < region.seedY + mc.MinSeedRange:
  1172. return True
  1173. #Check for edge
  1174. if seedX < mc.MinEdgeRange or seedX >= (mapSize.MapWidth + 1) - mc.MinEdgeRange:
  1175. return True
  1176. if seedY < mc.MinEdgeRange or seedY >= (mapSize.MapHeight + 1) - mc.MinEdgeRange:
  1177. return True
  1178. return False
  1179. def getRegionByID(self,ID):
  1180. for region in self.regionList:
  1181. if region.ID == ID:
  1182. return region
  1183. return None
  1184. def PrintRegionMap(self,bShowWater):
  1185. print "Region Map"
  1186. for y in range(mapSize.MapHeight - 1,-1,-1):
  1187. lineString = ""
  1188. for x in range(mapSize.MapWidth):
  1189. mapLoc = self.regionMap[GetIndex(x,y)]
  1190. region = self.getRegionByID(mapLoc)
  1191. if mapLoc == -1:
  1192. lineString += "X"
  1193. elif bShowWater and region.isWater == True:
  1194. lineString += " "
  1195. else:
  1196. lineString += chr(mapLoc + 33)
  1197. print lineString
  1198. lineString = " "
  1199. print lineString
  1200. def PrintRegionRxMap(self,bShowWater):
  1201. print "Region Map"
  1202. for y in range(mapSize.MapHeight,-1,-1):
  1203. lineString = ""
  1204. for x in range(mapSize.MapWidth + 1):
  1205. mapLoc = self.regionRxMap[GetRxIndex(x,y)]
  1206. region = self.getRegionByID(mapLoc)
  1207. if mapLoc == -1:
  1208. lineString += "X"
  1209. elif bShowWater and region.isWater == True:
  1210. lineString += " "
  1211. else:
  1212. lineString += chr(mapLoc + 33)
  1213. print lineString
  1214. lineString = " "
  1215. print lineString
  1216. def PrintRegionList(self):
  1217. print "Number of regions = %(n)d" % {"n":len(self.regionList)}
  1218. for region in self.regionList:
  1219. print str(region)
  1220. return
  1221. regMap = RegionMap()
  1222. class RegionPlot :
  1223. def __init__(self,ID,x,y):
  1224. self.regionID = ID
  1225. self.x = x
  1226. self.y = y
  1227. self.gateRx = -1
  1228. self.bBorder = False
  1229. self.bEdge = False
  1230. class Region :
  1231. def __init__(self,ID,seedX,seedY):
  1232. self.ID = ID
  1233. self.seedX = seedX
  1234. self.seedY = seedY
  1235. self.isGrowing = True
  1236. self.neighborList = list()
  1237. self.gateRegion = -1
  1238. self.gatePlot = None
  1239. self.plotList = list()
  1240. self.isWater = False
  1241. self.isTouchingNeighbor = False
  1242. self.altitude = 0.0
  1243. self.moisture = 1.0
  1244. def __str__(self):
  1245. string = "ID=%(id)d(%(c)s), size=%(s)d, altitude=%(a)d \n" % {"id":self.ID,"c":chr(self.ID + 33),"s":len(self.plotList),"a":self.altitude}
  1246. string += "gateRegion=%(id)d(%(c)s) \n" % {"id":self.gateRegion,"c":chr(self.gateRegion + 33)}
  1247. string += " " + self.NeighborListString() + "\n"
  1248. return string
  1249. def NeighborListString(self):
  1250. string = "["
  1251. for ID in self.neighborList:
  1252. string += chr(ID + 33) + ","
  1253. string += "]"
  1254. return string
  1255. def getWaterNeighborCount(self):
  1256. count = 0
  1257. for regionID in self.neighborList:
  1258. region = regMap.getRegionByID(regionID)
  1259. if region.isWater == True:
  1260. count += 1
  1261. return count
  1262. def getBorderPlotList(self,neighborID):
  1263. borderPlotList = list()
  1264. borderPlotCount = 0
  1265. for plot in self.plotList:
  1266. if plot.bBorder == True:
  1267. borderPlotCount += 1
  1268. for direction in range(1,5,1):
  1269. if direction == 1:#N
  1270. xx = plot.x
  1271. yy = plot.y + 1
  1272. elif direction == 2:#S
  1273. xx = plot.x
  1274. yy = plot.y - 1
  1275. elif direction == 3:#E
  1276. xx = plot.x + 1
  1277. yy = plot.y
  1278. else:#W
  1279. xx = plot.x - 1
  1280. yy = plot.y
  1281. ii = GetIndex(xx,yy)
  1282. if ii != -1 and regMap.regionMap[ii] == neighborID:
  1283. borderPlotList.append(plot)
  1284. break
  1285. print "borderPlotCount=%(bc)d" % {"bc":borderPlotCount}
  1286. return borderPlotList
  1287. def getGateListToNeighbor(self,neighborID):
  1288. gateListToNeighbor = list()
  1289. for rPlot in self.gateList:
  1290. if riverMap.isRxTouchingRegion(rPlot.x,rPlot.y,neighborID):
  1291. gateListToNeighbor.append(rPlot)
  1292. ## print "%(ng)d gates from %(s)d to %(n)d" % \
  1293. ## {"ng":len(gateListToNeighbor),"s":self.ID,"n":neighborID}
  1294. return gateListToNeighbor
  1295. def defineValidGateList(self):
  1296. #This function is called in createFlowMap so the riverMap functions
  1297. #can be called from here. We now complile a list of all possible river
  1298. #gates
  1299. self.gateList = list()
  1300. for rxY in range(mapSize.MapHeight + 1):
  1301. for rxX in range(mapSize.MapWidth + 1):
  1302. if riverMap.isRxTouchingRegion(rxX,rxY,self.ID):
  1303. if riverMap.isValidFullGate(self.ID,rxX,rxY):
  1304. rPlot = RiverPlot(rxX,rxY,-1,self.ID)
  1305. self.gateList.append(rPlot)
  1306. return
  1307. def expandWaterRegion(self):
  1308. expanded = False
  1309. for plot in self.plotList:
  1310. for direction in range(1,5,1):
  1311. if direction == 1:#N
  1312. xx = plot.x
  1313. yy = plot.y + 1
  1314. elif direction == 2:#S
  1315. xx = plot.x
  1316. yy = plot.y - 1
  1317. elif direction == 3:#E
  1318. xx = plot.x + 1
  1319. yy = plot.y
  1320. else:#W
  1321. xx = plot.x - 1
  1322. yy = plot.y
  1323. ii = GetIndex(xx,yy)
  1324. if ii != -1 and regMap.regionMap[ii] == -1:
  1325. naPlot = RegionPlot(self.ID,xx,yy)
  1326. regMap.regionMap[ii] = self.ID
  1327. self.plotList.append(naPlot)
  1328. expanded = True
  1329. break
  1330. return expanded
  1331. def getGatedNeighborList(self):
  1332. gatedList = list()
  1333. for regionID in self.neighborList:
  1334. region = regMap.getRegionByID(regionID)
  1335. if region.isWater or region.gateRegion != -1:
  1336. validGateList = self.getGateListToNeighbor(regionID)
  1337. if len(validGateList) > 0:
  1338. gatedList.append(region.ID)
  1339. return gatedList
  1340. def getDistanceToClosestBorderPlot(self,plot):
  1341. minDistance = 100.0
  1342. for bPlot in self.plotList:
  1343. if bPlot.bEdge == False:
  1344. continue
  1345. distance = GetDistance(plot.x,plot.y,bPlot.x,bPlot.y)
  1346. if distance < minDistance:
  1347. minDistance = distance
  1348. return minDistance
  1349. #In this case the center is the plot farthest from any border
  1350. def getCenter(self):
  1351. maxDistance = 0.0
  1352. center = None
  1353. for plot in self.plotList:
  1354. distance = self.getDistanceToClosestBorderPlot(plot)
  1355. if maxDistance < distance:
  1356. maxDistance = distance
  1357. ## print "maxDistance= %(m)f, plot.x= %(x)d, plot.y=%(y)d" % \
  1358. ## {"m":maxDistance,"x":plot.x,"y":plot.y}
  1359. center = plot
  1360. return center
  1361. class RiverMap :
  1362. def __init__(self):
  1363. return
  1364. def createRiverMap(self):
  1365. self.createFlowMap()
  1366. self.calculateWetAndDry()
  1367. self.riverMap = array('f')
  1368. for i in range((mapSize.MapHeight + 1) * (mapSize.MapWidth + 1)):
  1369. self.riverMap.append(0)
  1370. for y in range(mapSize.MapHeight + 1):
  1371. for x in range(mapSize.MapWidth + 1):
  1372. i = self.getRiverIndex(x,y)
  1373. direction = self.flowMap[i]
  1374. regionID = self.getRegion(x,y)
  1375. region = regMap.getRegionByID(regionID)
  1376. xx = x
  1377. yy = y
  1378. while direction != -1 and direction != self.L:
  1379. xx,yy = self.getXYFromDirection(xx,yy,direction)
  1380. ii = self.getRiverIndex(xx,yy)
  1381. self.riverMap[ii] += mc.MinRainfall + (1.0 - mc.MinRainfall) * region.moisture
  1382. direction = self.flowMap[ii]
  1383. return
  1384. def createFlowMap(self):
  1385. #Start with an outflow from the region, then randomly decide which neighbors
  1386. #will flow into this square by how many choices that neighbor has. If the
  1387. #neighbor has only one choice, then the chance is 100 percent. At least
  1388. #one neighbor must be chosen unless it is not possible, otherwise the
  1389. #process might end before each tile is set. Then put each chosen neighbor
  1390. #on the stack to be processed the same way.
  1391. self.L = 0
  1392. self.N = 1
  1393. self.S = 2
  1394. self.E = 3
  1395. self.W = 4
  1396. self.NE = 5
  1397. self.NW = 6
  1398. self.SE = 7
  1399. self.SW = 8
  1400. self.heightMap = array('d')
  1401. self.flowMap = array('i')
  1402. for i in range((mapSize.MapHeight + 1) * (mapSize.MapWidth + 1)):
  1403. self.flowMap.append(-1)
  1404. self.heightMap.append(-1.0)
  1405. self.defineGates()
  1406. print "Gates Defined !!!!!!!!!!!!!!!!!!!!!!!!"
  1407. for region in regMap.regionList:
  1408. if region.isWater == True:
  1409. continue
  1410. #randomly choose an outflow gate
  1411. ## print "region.gateRegion = %(gr)d" % {"gr":region.gateRegion}
  1412. validGateList = region.getGateListToNeighbor(region.gateRegion)
  1413. if len(validGateList) == 0:
  1414. print "validGateList == 0!!!!!!!!!!!!!!!!!!!!"
  1415. print "region = %(r)s" % {"r":str(region)}
  1416. gRegion = regMap.getRegionByID(region.gateRegion)
  1417. print "gateRegion = %(g)s" % {"g":str(gRegion)}
  1418. raise ValueError, "region has neighbor but no valid gates. see debug file"
  1419. region.gatePlot = validGateList[PRand.randint(0,len(validGateList)-1)]
  1420. rxX = region.gatePlot.x
  1421. rxY = region.gatePlot.y
  1422. rxI = self.getRiverIndex(rxX,rxY)
  1423. #set flow so that it is pointing out of region
  1424. iterations = 0
  1425. while(True):
  1426. iterations += 1
  1427. if iterations > 100:
  1428. raise ValueError, "endless loop in gate setter"
  1429. gateRegion = regMap.getRegionByID(region.gateRegion)
  1430. if gateRegion.isWater:
  1431. self.flowMap[rxI] = self.L
  1432. self.heightMap[rxI] = 0.01
  1433. break
  1434. #pick random cardinal direction
  1435. direction = PRand.randint(1,4)
  1436. ## print direction
  1437. xx,yy = self.getXYFromDirection(rxX,rxY,direction)
  1438. if self.isRxInRegion(xx,yy,region.gateRegion):
  1439. self.flowMap[rxI] = direction
  1440. self.heightMap[rxI] = 0.01
  1441. break
  1442. #Now create heightmap. Start from each gate and increase altitude of
  1443. #neighbors by a random percentage, and then place each neighbor on a
  1444. #queue for similar processing. Randomize the queue order for each pass.
  1445. #This method should avoid lakes.
  1446. #Place all gates on queue.
  1447. plotList = list()
  1448. regMap.PrintRegionList()
  1449. for region in regMap.regionList:
  1450. if region.gatePlot == None:
  1451. continue
  1452. rxX = region.gatePlot.x
  1453. rxY = region.gatePlot.y
  1454. ## print "rxX=%(x)d, rxY=%(y)d" % {"x":rxX,"y":rxY}
  1455. riverPlot = RiverPlot(rxX,rxY,0,region.ID)
  1456. plotList.append(riverPlot)
  1457. ## print "hi"
  1458. while(len(plotList) > 0):
  1459. ## print "len plotList = v"
  1460. ## print len(plotList)
  1461. count = len(plotList)
  1462. plotList = ShuffleList(plotList)
  1463. for n in range(count):
  1464. thisPlot = plotList.pop(0)#queue method, not stack
  1465. ## print "popping"
  1466. rxI = self.getRiverIndex(thisPlot.x,thisPlot.y)
  1467. altitude = self.heightMap[rxI]
  1468. for direction in range(1,5,1):
  1469. x,y = self.getXYFromDirection(thisPlot.x,thisPlot.y,direction)
  1470. rxII = self.getRiverIndex(x,y)
  1471. ## print "rxII=%(i)d, x=%(x)d, y=%(y)d, heightMap=%(h)f, isRxInRegion=%(ir)d" % \
  1472. ## {"i":rxII,"x":x,"y":y,"h":self.heightMap[rxII],"ir":self.isRxInRegion(x,y,thisPlot.regionID)}
  1473. if rxII != -1 and self.heightMap[rxII] == -1.0 and \
  1474. self.isRxInRegion(x,y,thisPlot.regionID):
  1475. randomScaler = 1.0 + float(PRand.randint(1,20))/100.0
  1476. self.heightMap[rxII] = altitude * randomScaler
  1477. newPlot = RiverPlot(x,y,0,thisPlot.regionID)
  1478. plotList.append(newPlot)
  1479. ## print "newPlot appended"
  1480. #Create flow map
  1481. for y in range(mapSize.MapHeight + 1):
  1482. for x in range(mapSize.MapWidth + 1):
  1483. paths = self.getPossiblePaths(x,y)
  1484. if len(paths) > 0:
  1485. i = self.getRiverIndex(x,y)
  1486. pathIndex = PRand.randint(0,len(paths)-1)
  1487. self.flowMap[i] = paths[pathIndex]
  1488. return
  1489. #Dryness should be calculated by getting the highest altitude
  1490. #region and making it's base the wettest region. Then eliminate
  1491. #those regions from the list. Then get the highest of the remaining
  1492. #regions and make it's base the dryest region.
  1493. def calculateWetAndDry(self):
  1494. regionList = list()
  1495. for region in regMap.regionList:
  1496. regionList.append(region)
  1497. regionList.sort(lambda x,y:cmp(x.altitude,y.altitude))
  1498. regionList.reverse()
  1499. region = regionList[0]
  1500. while(region.altitude > 0):
  1501. region = regMap.getRegionByID(region.gateRegion)
  1502. if region.altitude == 1:
  1503. self.wetSpot = riverMap.plotFromRx(region.gatePlot.x,region.gatePlot.y,riverMap.SW)
  1504. #Now calculate moisture for each region
  1505. minMoisture = 1.0
  1506. for region in regMap.regionList:
  1507. gate = region.gatePlot
  1508. if gate == None:
  1509. continue
  1510. wetSpotX,wetSpotY = self.wetSpot
  1511. distance = GetDistance(gate.x,gate.y,wetSpotX,wetSpotY)
  1512. region.moisture = 1.0 - distance/float(mapSize.MapWidth)
  1513. minMoisture = min(region.moisture,minMoisture)
  1514. scaler = 1.0/(1.0 - minMoisture)
  1515. for region in regMap.regionList:
  1516. region.moisture = (region.moisture - minMoisture) * scaler
  1517. return
  1518. def defineGates(self):
  1519. #Now each region picks one gate that is not in the current gate line
  1520. #to avoid recursive loops
  1521. numRegions = len(regMap.regionList)
  1522. numGatesPlaced = 0
  1523. iterations = 0
  1524. #water is considered gated for this purpose
  1525. for region in regMap.regionList:
  1526. region.defineValidGateList()
  1527. #regions should always have gates
  1528. if len(region.gateList) == 0:
  1529. print str(region)
  1530. print "has no gates!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
  1531. regMap.PrintRegionMap(False)
  1532. raise ValueError, "region has no gates"
  1533. while numGatesPlaced < numRegions:
  1534. if iterations > 500:
  1535. raise ValueError, "Endless loop occured in gate placement"
  1536. break
  1537. else:
  1538. iterations += 1
  1539. regMap.regionList = ShuffleList(regMap.regionList)
  1540. for region in regMap.regionList:
  1541. if region.gateRegion == -1:
  1542. gatedNeighborList = region.getGatedNeighborList()
  1543. if len(gatedNeighborList) > 0:
  1544. gatedNeighborList = ShuffleList(gatedNeighborList)
  1545. region.gateRegion = gatedNeighborList[0]
  1546. if region.isWater:
  1547. region.altitude = 0
  1548. else:
  1549. gateRegion = regMap.getRegionByID(region.gateRegion)
  1550. region.altitude = gateRegion.altitude + 1
  1551. ## print "region %(r)d gateRegion is %(g)d" % \
  1552. ## {"r":region.ID,"g":region.gateRegion}
  1553. numGatesPlaced += 1
  1554. def isValidHalfGate(self,regionID,rxX,rxY):
  1555. #A valid half gate is a rx that is not in a region, touches
  1556. #only 2 regions and is 4-connected to an rx that is in the region
  1557. regionList = list()
  1558. for direction in range(5,9,1):
  1559. px,py = self.plotFromRx(rxX,rxY,direction)
  1560. i = GetIndex(px,py)
  1561. pRegID = regMap.regionMap[i]
  1562. if pRegID == -1:
  1563. return False
  1564. AppendUnique(regionList,pRegID)
  1565. if len(regionList) != 2:
  1566. return False
  1567. if self.isRxInRegion(rxX,rxY,regionID):
  1568. return False
  1569. for direction in range(1,5,1):
  1570. xx,yy = self.getXYFromDirection(rxX,rxY,direction)
  1571. if self.isRxInRegion(xx,yy,regionID):
  1572. return True
  1573. return False
  1574. def isValidFullGate(self,regionID,rxX,rxY):
  1575. if not self.isValidHalfGate(regionID,rxX,rxY):
  1576. return False
  1577. region = regMap.getRegionByID(regionID)
  1578. for nRegionID in region.neighborList:
  1579. if self.isValidHalfGate(nRegionID,rxX,rxY):
  1580. return True
  1581. for direction in range(1,5,1):
  1582. xx,yy = self.getXYFromDirection(rxX,rxY,direction)
  1583. if self.isValidHalfGate(nRegionID,rxX,rxY):
  1584. return True
  1585. return False
  1586. def getPossiblePaths(self,rxX,rxY):
  1587. possiblePaths = list()
  1588. regionID = self.getRegion(rxX,rxY)
  1589. if regionID == -1:
  1590. return possiblePaths
  1591. region = regMap.getRegionByID(regionID)
  1592. if region.isWater == True:
  1593. return possiblePaths
  1594. rxI = self.getRiverIndex(rxX,rxY)
  1595. altitude = self.heightMap[rxI]
  1596. rejectedDirection = self.L
  1597. for direction in range(1,5,1):
  1598. x,y = self.getXYFromDirection(rxX,rxY,direction)
  1599. i = self.getRiverIndex(x,y)
  1600. if self.isRxInRegion(x,y,regionID):
  1601. if self.heightMap[i] > altitude:
  1602. if rejectedDirection == self.L:
  1603. rejectedDirection = self.getOppositeDirection(direction)
  1604. else:
  1605. rejectedDirection = self.L
  1606. for direction in range(1,5,1):
  1607. x,y = self.getXYFromDirection(rxX,rxY,direction)
  1608. if self.isRxInRegion(x,y,regionID) or \
  1609. (x == region.gatePlot.x and y == region.gatePlot.y) :
  1610. i = self.getRiverIndex(x,y)
  1611. if i != -1 and self.heightMap[i] < altitude:
  1612. possiblePaths.append(direction)
  1613. if len(possiblePaths) > 1:
  1614. for n in range(len(possiblePaths)):
  1615. if rejectedDirection == possiblePaths[n]:
  1616. del possiblePaths[n]
  1617. break
  1618. return possiblePaths
  1619. def fillInLake(self,rxX,rxY):
  1620. rxI = self.getRiverIndex(rxX,rxY)
  1621. altitude = self.heightMap[rxI]
  1622. regionID = self.getRegion(rxX,rxY)
  1623. lowestNeighbor = 1.0
  1624. for direction in range(1,5,1):
  1625. x,y = self.getXYFromDirection(rxX,rxY,direction)
  1626. i = self.getRiverIndex(x,y)
  1627. if self.isRxInRegion(x,y,regionID) == True:
  1628. if self.heightMap[i] < lowestNeighbor:
  1629. lowestNeighbor = self.heightMap[i]
  1630. if altitude < lowestNeighbor:
  1631. self.heightMap[rxI] = altitude + ((lowestNeighbor - altitude)/2.0)
  1632. else:
  1633. self.heightMap[rxI] = altitude * 1.05
  1634. def isLake(self,rxX,rxY):
  1635. rxI = self.getRiverIndex(rxX,rxY)
  1636. altitude = self.heightMap[rxI]
  1637. regionID = self.getRegion(rxX,rxY)
  1638. lowestNeighbor = 1.0
  1639. for direction in range(1,5,1):
  1640. x,y = self.getXYFromDirection(rxX,rxY,direction)
  1641. i = self.getRiverIndex(x,y)
  1642. if self.isRxInRegion(x,y,regionID) == True:
  1643. if self.heightMap[i] < lowestNeighbor:
  1644. lowestNeighbor = self.heightMap[i]
  1645. if lowestNeighbor >= altitude:
  1646. return True
  1647. return False
  1648. def isOutFlowGate(self,rxX,rxY):
  1649. for region in regMap.regionList:
  1650. if region.isWater == False:
  1651. gateRxX,gateRxY = self.rxFromPlot(region.gatePlot.x,region.gatePlot.y,self.SW)
  1652. if gateRxX == rxX and gateRxY == rxY:
  1653. return True
  1654. return False
  1655. def getOppositeDirection(self,direction):
  1656. opposite = self.L
  1657. if direction == self.N:
  1658. opposite = self.S
  1659. elif direction == self.S:
  1660. opposite = self.N
  1661. elif direction == self.E:
  1662. opposite = self.W
  1663. elif direction == self.W:
  1664. opposite = self.E
  1665. return opposite
  1666. def getXYFromDirection(self,x,y,direction):
  1667. xx = x
  1668. yy = y
  1669. if direction == self.N:
  1670. yy += 1
  1671. elif direction == self.S:
  1672. yy -= 1
  1673. elif direction == self.E:
  1674. xx += 1
  1675. elif direction == self.W:
  1676. xx -= 1
  1677. return xx,yy
  1678. def getRiverIndex(self,x,y):
  1679. if x < 0 or x >= mapSize.MapWidth + 1:
  1680. return -1
  1681. else:
  1682. xx = x
  1683. if y < 0 or y >= mapSize.MapHeight + 1:
  1684. return -1
  1685. else:
  1686. yy = y
  1687. i = yy * (mapSize.MapWidth + 1) + xx
  1688. return i
  1689. def isRxInRegion(self,x,y,regionID):
  1690. #Rxs on the border are not in region. All plots touching rx must
  1691. #be in region
  1692. for direction in range(5,9,1):
  1693. xx,yy = self.plotFromRx(x,y,direction)
  1694. i = GetIndex(xx,yy)
  1695. if i == -1 or regMap.regionMap[i] != regionID:
  1696. return False
  1697. return True
  1698. def getRegion(self,x,y):
  1699. #Rxs on the border are not in region. All plots touching rx must
  1700. #be in region, unless this is the gate for that region
  1701. xx,yy = self.plotFromRx(x,y,self.SW)
  1702. i = GetIndex(xx,yy)
  1703. regionID = regMap.regionMap[i]
  1704. invalidRegion = False
  1705. for direction in range(5,9,1):
  1706. xx,yy = self.plotFromRx(x,y,direction)
  1707. i = GetIndex(xx,yy)
  1708. nRegionID = regMap.regionMap[i]
  1709. if nRegionID == -1:
  1710. continue
  1711. #test if this main plot is gate for this region
  1712. nRegion = regMap.getRegionByID(nRegionID)
  1713. if nRegion.gatePlot != None and \
  1714. x == nRegion.gatePlot.x and y == nRegion.gatePlot.y:
  1715. return nRegionID
  1716. if nRegionID != regionID:
  1717. invalidRegion = True
  1718. if invalidRegion:
  1719. return -1
  1720. return regionID
  1721. def isRxTouchingRegion(self,x,y,regionID):
  1722. #Check all four plots
  1723. plotX,plotY = self.plotFromRx(x,y,self.NW)
  1724. i = GetIndex(plotX,plotY)
  1725. if i != -1 and regMap.regionMap[i] == regionID:
  1726. return True
  1727. plotX,plotY = self.plotFromRx(x,y,self.NE)
  1728. i = GetIndex(plotX,plotY)
  1729. if i != -1 and regMap.regionMap[i] == regionID:
  1730. return True
  1731. plotX,plotY = self.plotFromRx(x,y,self.SW)
  1732. i = GetIndex(plotX,plotY)
  1733. if i != -1 and regMap.regionMap[i] == regionID:
  1734. return True
  1735. plotX,plotY = self.plotFromRx(x,y,self.SE)
  1736. i = GetIndex(plotX,plotY)
  1737. if i != -1 and regMap.regionMap[i] == regionID:
  1738. return True
  1739. return False
  1740. def rxFromPlot(self,plotX,plotY,direction):
  1741. if direction == self.SW:
  1742. x = plotX
  1743. y = plotY
  1744. elif direction == self.SE:
  1745. x = plotX + 1
  1746. y = plotY
  1747. elif direction == self.NW:
  1748. x = plotX
  1749. y = plotY + 1
  1750. else:#NE
  1751. x = plotX + 1
  1752. y = plotY + 1
  1753. #check for validity
  1754. if x < 0 or x >= mapSize.MapWidth + 1:
  1755. return -1,-1
  1756. if y < 0 or y >= mapSize.MapHeight + 1:
  1757. return -1,-1
  1758. return x,y
  1759. def plotFromRx(self,rxX,rxY,direction):
  1760. if direction == self.NE:
  1761. x = rxX
  1762. y = rxY
  1763. elif direction == self.NW:
  1764. x = rxX - 1
  1765. y = rxY
  1766. elif direction == self.SE:
  1767. x = rxX
  1768. y = rxY - 1
  1769. else:#SW
  1770. x = rxX - 1
  1771. y = rxY - 1
  1772. #check for validity
  1773. if x < 0 or x >= mapSize.MapWidth:
  1774. return -1,-1
  1775. if y < 0 or y >= mapSize.MapHeight:
  1776. return -1,-1
  1777. return x,y
  1778. def PrintFlowMap(self):
  1779. print "Flow Map"
  1780. for y in range(mapSize.MapHeight,-1,-1):
  1781. lineString = ""
  1782. for x in range(mapSize.MapWidth + 1):
  1783. mapLoc = self.flowMap[self.getRiverIndex(x,y)]
  1784. if mapLoc == -1:
  1785. lineString += "X"
  1786. elif mapLoc == self.N:
  1787. lineString += "N"
  1788. elif mapLoc == self.S:
  1789. lineString += "S"
  1790. elif mapLoc == self.E:
  1791. lineString += "E"
  1792. elif mapLoc == self.W:
  1793. lineString += "W"
  1794. else:
  1795. lineString += "X"
  1796. print lineString
  1797. lineString = " "
  1798. print lineString
  1799. riverMap = RiverMap()
  1800. class RiverPlot :
  1801. def __init__(self,x,y,direction,regionID):
  1802. self.x = x
  1803. self.y = y
  1804. self.direction = direction
  1805. self.regionID = regionID
  1806. return
  1807. class PlotMap :
  1808. def __init__(self):
  1809. return
  1810. def createPlotMap(self):
  1811. self.OCEAN = 0
  1812. self.LAND = 1
  1813. self.HILLS = 2
  1814. self.PEAK = 3
  1815. self.L = 0
  1816. self.N = 1
  1817. self.S = 2
  1818. self.E = 3
  1819. self.W = 4
  1820. self.NE = 5
  1821. self.NW = 6
  1822. self.SE = 7
  1823. self.SW = 8
  1824. self.plotMap = array('i')
  1825. scrambledPlotList = list()
  1826. regMap.regionList.sort(lambda n,m: cmp(n.altitude,m.altitude))
  1827. regMap.regionList.reverse()
  1828. regMap.highestRegionAltitude = regMap.regionList[0].altitude
  1829. for y in range(mapSize.MapHeight):
  1830. for x in range(mapSize.MapWidth):
  1831. self.plotMap.append(self.OCEAN)
  1832. scrambledPlotList.append((x,y))
  1833. scrambledPlotList = ShuffleList(scrambledPlotList)
  1834. for n in range(len(scrambledPlotList)):
  1835. x,y = scrambledPlotList[n]
  1836. i = GetIndex(x,y)
  1837. if self.shouldPlacePeak(x,y):
  1838. if self.plotMap[i] != self.HILLS:
  1839. self.plotMap[i] = self.PEAK
  1840. else:
  1841. regionID = regMap.regionMap[i]
  1842. region = regMap.getRegionByID(regionID)
  1843. if not region.isWater:
  1844. self.plotMap[i] = self.LAND
  1845. self.placeLandInWater(x,y)
  1846. for n in range(len(scrambledPlotList)):
  1847. x,y = scrambledPlotList[n]
  1848. i = GetIndex(x,y)
  1849. regionID = regMap.regionMap[i]
  1850. if regionID == -1:
  1851. continue
  1852. region = regMap.getRegionByID(regionID)
  1853. if region.isWater and plotMap.plotMap[i] != plotMap.OCEAN:
  1854. for direction in range(1,5,1):
  1855. xx,yy = self.getXYFromDirection(x,y,direction)
  1856. ii = GetIndex(xx,yy)
  1857. nRegionID = regMap.regionMap[ii]
  1858. if nRegionID == -1:
  1859. continue
  1860. nRegion = regMap.getRegionByID(nRegionID)
  1861. if not nRegion.isWater:
  1862. regMap.regionMap[i] = nRegionID
  1863. break
  1864. for n in range(len(scrambledPlotList)):
  1865. x,y = scrambledPlotList[n]
  1866. i = GetIndex(x,y)
  1867. #Decide if hill or peak should be here
  1868. if self.plotMap[i] == self.LAND:
  1869. altitude = GetPlotAltitude(x,y)
  1870. hillChanceRange = mc.HillChanceAtOne - mc.HillChanceAtZero
  1871. hillChance = mc.HillChanceAtZero + (altitude * hillChanceRange)
  1872. if PRand.random() < hillChance:
  1873. self.plotMap[i] = self.HILLS
  1874. peakChanceRange = mc.PeakChanceAtOne - mc.PeakChanceAtZero
  1875. peakChance = mc.PeakChanceAtZero + (altitude * peakChanceRange)
  1876. if PRand.random() < peakChance:
  1877. self.plotMap[i] = self.PEAK
  1878. #now there's a chance to flatten it again!
  1879. if self.plotMap[i] != self.LAND:
  1880. riverSize = GetRiverSize(x,y)
  1881. maxRiverSize = float(mc.RiverThreshold) * mc.RiverFactorFlattensAll
  1882. riverSize = min(maxRiverSize,riverSize)
  1883. flattenChance = riverSize/maxRiverSize
  1884. ## print flattenChance
  1885. if PRand.random() < flattenChance:
  1886. self.plotMap[i] = self.LAND
  1887. #now make sure that rivers are not flowing between peaks
  1888. if self.plotMap[i] == self.PEAK:
  1889. if self.shouldFlattenRiverPeak(x,y):
  1890. riverSize = GetRiverSize(x,y)
  1891. maxRiverSize = float(mc.RiverThreshold) * mc.RiverFactorFlattensAll
  1892. if riverSize > maxRiverSize:
  1893. self.plotMap[i] = self.LAND
  1894. else:
  1895. self.plotMap[i] = self.HILLS
  1896. #Now for SoftenPeakPercent of peaks, make them hills
  1897. for y in range(1,mapSize.MapHeight - 1):
  1898. for x in range(1,mapSize.MapWidth - 1):
  1899. i = GetIndex(x,y)
  1900. if self.plotMap[i] == self.PEAK:
  1901. if mc.SoftenPeakPercent >= PRand.random():
  1902. self.plotMap[i] = self.HILLS
  1903. #Now make sure there are no passable areas that are blocked in
  1904. ## self.PrintPlotMap()
  1905. areaMap = Areamap(mapSize.MapWidth,mapSize.MapHeight)
  1906. areaMap.findImpassableAreas()
  1907. ## areaMap.PrintAreaMap()
  1908. for i in range(mapSize.MapWidth*mapSize.MapHeight):
  1909. if areaMap.areaMap[i] == 0:
  1910. if self.plotMap[i] != self.PEAK:
  1911. self.plotMap[i] = self.PEAK
  1912. else:
  1913. areaMap.areaMap[i] = 1
  1914. ## areaMap.PrintAreaMap()
  1915. def shouldFlattenRiverPeak(self,x,y):
  1916. direction = riverMap.NW
  1917. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  1918. rxI = riverMap.getRiverIndex(rxX,rxY)
  1919. if riverMap.riverMap[rxI] > mc.RiverThreshold:
  1920. pDir = direction
  1921. xx,yy = self.getXYFromDirection(x,y,pDir)
  1922. ii = GetIndex(xx,yy)
  1923. if self.plotMap[ii] == self.PEAK:
  1924. return True
  1925. if riverMap.flowMap[rxI] == riverMap.E:
  1926. pDir = self.N
  1927. xx,yy = self.getXYFromDirection(x,y,pDir)
  1928. ii = GetIndex(xx,yy)
  1929. if self.plotMap[ii] == self.PEAK:
  1930. return True
  1931. if riverMap.flowMap[rxI] == riverMap.S:
  1932. pDir = self.W
  1933. xx,yy = self.getXYFromDirection(x,y,pDir)
  1934. ii = GetIndex(xx,yy)
  1935. if self.plotMap[ii] == self.PEAK:
  1936. return True
  1937. direction = riverMap.NE
  1938. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  1939. rxI = riverMap.getRiverIndex(rxX,rxY)
  1940. if riverMap.riverMap[rxI] > mc.RiverThreshold:
  1941. pDir = direction
  1942. xx,yy = self.getXYFromDirection(x,y,pDir)
  1943. ii = GetIndex(xx,yy)
  1944. if self.plotMap[ii] == self.PEAK:
  1945. return True
  1946. if riverMap.flowMap[rxI] == riverMap.W:
  1947. pDir = self.N
  1948. xx,yy = self.getXYFromDirection(x,y,pDir)
  1949. ii = GetIndex(xx,yy)
  1950. if self.plotMap[ii] == self.PEAK:
  1951. return True
  1952. if riverMap.flowMap[rxI] == riverMap.S:
  1953. pDir = self.E
  1954. xx,yy = self.getXYFromDirection(x,y,pDir)
  1955. ii = GetIndex(xx,yy)
  1956. if self.plotMap[ii] == self.PEAK:
  1957. return True
  1958. direction = riverMap.SE
  1959. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  1960. rxI = riverMap.getRiverIndex(rxX,rxY)
  1961. if riverMap.riverMap[rxI] > mc.RiverThreshold:
  1962. pDir = direction
  1963. xx,yy = self.getXYFromDirection(x,y,pDir)
  1964. ii = GetIndex(xx,yy)
  1965. if self.plotMap[ii] == self.PEAK:
  1966. return True
  1967. if riverMap.flowMap[rxI] == riverMap.W:
  1968. pDir = self.S
  1969. xx,yy = self.getXYFromDirection(x,y,pDir)
  1970. ii = GetIndex(xx,yy)
  1971. if self.plotMap[ii] == self.PEAK:
  1972. return True
  1973. if riverMap.flowMap[rxI] == riverMap.N:
  1974. pDir = self.E
  1975. xx,yy = self.getXYFromDirection(x,y,pDir)
  1976. ii = GetIndex(xx,yy)
  1977. if self.plotMap[ii] == self.PEAK:
  1978. return True
  1979. direction = riverMap.SW
  1980. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  1981. rxI = riverMap.getRiverIndex(rxX,rxY)
  1982. if riverMap.riverMap[rxI] > mc.RiverThreshold:
  1983. pDir = direction
  1984. xx,yy = self.getXYFromDirection(x,y,pDir)
  1985. ii = GetIndex(xx,yy)
  1986. if self.plotMap[ii] == self.PEAK:
  1987. return True
  1988. if riverMap.flowMap[rxI] == riverMap.E:
  1989. pDir = self.S
  1990. xx,yy = self.getXYFromDirection(x,y,pDir)
  1991. ii = GetIndex(xx,yy)
  1992. if self.plotMap[ii] == self.PEAK:
  1993. return True
  1994. if riverMap.flowMap[rxI] == riverMap.N:
  1995. pDir = self.W
  1996. xx,yy = self.getXYFromDirection(x,y,pDir)
  1997. ii = GetIndex(xx,yy)
  1998. if self.plotMap[ii] == self.PEAK:
  1999. return True
  2000. return False
  2001. def placeLandInWater(self,x,y):
  2002. i = GetIndex(x,y)
  2003. regionID = regMap.regionMap[i]
  2004. if regionID == -1:
  2005. return False
  2006. region = regMap.getRegionByID(regionID)
  2007. borderPlotIsLand = False
  2008. for direction in range(1,5,1):
  2009. xx,yy = self.getXYFromDirection(x,y,direction)
  2010. ii = GetIndex(xx,yy)
  2011. if ii == -1:
  2012. continue
  2013. if self.plotMap[ii] != self.OCEAN and \
  2014. regMap.regionMap[ii] != regionID:
  2015. if IsPlotTouchingRiver(x,y):
  2016. oceanNeighborTouchingRiver = False
  2017. for dir2 in range(1,5,1):
  2018. xxx,yyy = self.getXYFromDirection(x,y,dir2)
  2019. iii = GetIndex(xxx,yyy)
  2020. if self.plotMap[iii] == self.OCEAN and \
  2021. IsPlotTouchingRiver(xxx,yyy):
  2022. oceanNeighborTouchingRiver = True
  2023. if oceanNeighborTouchingRiver == False:
  2024. continue
  2025. oppDirection = self.getOppositeDirection(direction)
  2026. xxx,yyy = self.getXYFromDirection(x,y,oppDirection)
  2027. if not IsPlotSurroundedByOcean(xxx,yyy):
  2028. continue
  2029. if PRand.randint(0,1) == 0:
  2030. nRegion = regMap.getRegionByID(regMap.regionMap[ii])
  2031. if nRegion != None:
  2032. print "placing land in water"
  2033. if nRegion.altitude < 2:
  2034. self.plotMap[i] = self.LAND
  2035. elif nRegion.altitude < 3 and regMap.highestRegionAltitude >= 3:
  2036. self.plotMap[i] = self.HILLS
  2037. else:
  2038. self.plotMap[i] = self.PEAK
  2039. return False
  2040. def getOppositeDirection(self,direction):
  2041. opposite = self.L
  2042. if direction == self.N:
  2043. opposite = self.S
  2044. elif direction == self.S:
  2045. opposite = self.N
  2046. elif direction == self.E:
  2047. opposite = self.W
  2048. elif direction == self.W:
  2049. opposite = self.E
  2050. elif direction == self.NW:
  2051. opposite = self.SE
  2052. elif direction == self.SE:
  2053. opposite = self.NW
  2054. elif direction == self.SW:
  2055. opposite = self.NE
  2056. elif direction == self.NE:
  2057. opposite = self.SW
  2058. return opposite
  2059. def shouldPlacePeak(self,x,y):
  2060. i = GetIndex(x,y)
  2061. regionID = regMap.regionMap[i]
  2062. if regionID == -1:
  2063. return True #Plots without a region are always peaks
  2064. region = regMap.getRegionByID(regionID)
  2065. if region.isWater:
  2066. return False #Water regions have no peaks
  2067. #if neighbor in different region not peak, then return True
  2068. for direction in range(1,9,1):
  2069. xx,yy = self.getXYFromDirection(x,y,direction)
  2070. ii = GetIndex(xx,yy)
  2071. if ii == -1:
  2072. return True #Land plots on map edge are peaks, water handled above
  2073. if self.plotMap[ii] != self.PEAK:
  2074. nRegionID = regMap.regionMap[ii]
  2075. if nRegionID == -1:
  2076. continue
  2077. ## if nRegionID == region.gateRegion:
  2078. nRegion = regMap.getRegionByID(nRegionID)
  2079. if nRegion.isWater and region.altitude < 2:
  2080. return False
  2081. elif nRegion.isWater and region.altitude < 3 and \
  2082. regMap.highestRegionAltitude >= 3:
  2083. self.plotMap[i] = self.HILLS #Cheating sorta
  2084. return True
  2085. if nRegionID != regionID:
  2086. return True
  2087. return False
  2088. def getXYFromDirection(self,x,y,direction):
  2089. xx = x
  2090. yy = y
  2091. if direction == self.N:
  2092. yy += 1
  2093. elif direction == self.S:
  2094. yy -= 1
  2095. elif direction == self.E:
  2096. xx += 1
  2097. elif direction == self.W:
  2098. xx -= 1
  2099. elif direction == self.NW:
  2100. yy += 1
  2101. xx -= 1
  2102. elif direction == self.NE:
  2103. yy += 1
  2104. xx += 1
  2105. elif direction == self.SW:
  2106. yy -= 1
  2107. xx -= 1
  2108. elif direction == self.SE:
  2109. yy -= 1
  2110. xx += 1
  2111. return xx,yy
  2112. def PrintPlotMap(self):
  2113. print "Plot Map"
  2114. for y in range(mapSize.MapHeight - 1,-1,-1):
  2115. lineString = ""
  2116. for x in range(mapSize.MapWidth):
  2117. mapLoc = self.plotMap[GetIndex(x,y)]
  2118. if mapLoc == self.OCEAN:
  2119. lineString += "O"
  2120. elif mapLoc == self.PEAK:
  2121. lineString += "P"
  2122. elif mapLoc == self.HILLS:
  2123. lineString += "H"
  2124. elif mapLoc == self.LAND:
  2125. lineString += "L"
  2126. print lineString
  2127. lineString = " "
  2128. print lineString
  2129. plotMap = PlotMap()
  2130. class TerrainMap :
  2131. def __init__(self):
  2132. return
  2133. def createTerrainMap(self):
  2134. self.L = 0
  2135. self.N = 1
  2136. self.S = 2
  2137. self.E = 3
  2138. self.W = 4
  2139. self.NE = 5
  2140. self.NW = 6
  2141. self.SE = 7
  2142. self.SW = 8
  2143. self.DESERT = 0
  2144. self.PLAINS = 1
  2145. self.ICE = 2
  2146. self.TUNDRA = 3
  2147. self.GRASS = 4
  2148. self.HILL = 5
  2149. self.COAST = 6
  2150. self.OCEAN = 7
  2151. self.PEAK = 8
  2152. self.MARSH = 9
  2153. self.terrainMap = array('i')
  2154. #initialize terrainMap with OCEAN
  2155. for i in range(0,mapSize.MapHeight*mapSize.MapWidth):
  2156. self.terrainMap.append(self.OCEAN)
  2157. for y in range(mapSize.MapHeight):
  2158. for x in range(mapSize.MapWidth):
  2159. i = GetIndex(x,y)
  2160. if plotMap.plotMap[i] != plotMap.OCEAN:
  2161. self.terrainMap[i] = self.GRASS
  2162. else:
  2163. for direction in range(1,9,1):
  2164. xx,yy = self.getXYFromDirection(x,y,direction)
  2165. ii = GetIndex(xx,yy)
  2166. if ii != -1 and plotMap.plotMap[ii] != plotMap.OCEAN:
  2167. self.terrainMap[i] = self.COAST
  2168. for y in range(mapSize.MapHeight):
  2169. for x in range(mapSize.MapWidth):
  2170. i = GetIndex(x,y)
  2171. if plotMap.plotMap[i] != plotMap.OCEAN:
  2172. rainFall = GetRainfall(x,y)
  2173. if rainFall < mc.DesertThreshold:
  2174. if rainFall < ((PRand.random()*mc.DesertThreshold)/2.0) + (mc.DesertThreshold/2.0):
  2175. self.terrainMap[i] = self.DESERT
  2176. else:
  2177. self.terrainMap[i] = self.PLAINS
  2178. elif rainFall < mc.PlainsThreshold:
  2179. if rainFall < ((PRand.random() * (mc.PlainsThreshold - mc.DesertThreshold))/2.0) + mc.DesertThreshold + ((mc.PlainsThreshold - mc.DesertThreshold)/2.0):
  2180. self.terrainMap[i] = self.PLAINS
  2181. else:
  2182. self.terrainMap[i] = self.GRASS
  2183. else:
  2184. self.terrainMap[i] = self.GRASS
  2185. altitude = GetPlotAltitude(x,y)
  2186. if altitude > mc.IceThreshold:
  2187. self.terrainMap[i] = self.ICE
  2188. elif altitude > mc.TundraThreshold:
  2189. self.terrainMap[i] = self.TUNDRA
  2190. elif altitude > mc.MaxDesertAltitude and self.terrainMap[i] == self.DESERT:
  2191. self.terrainMap[i] = self.PLAINS
  2192. def getXYFromDirection(self,x,y,direction):
  2193. xx = x
  2194. yy = y
  2195. if direction == self.N:
  2196. yy += 1
  2197. elif direction == self.S:
  2198. yy -= 1
  2199. elif direction == self.E:
  2200. xx += 1
  2201. elif direction == self.W:
  2202. xx -= 1
  2203. elif direction == self.NW:
  2204. yy += 1
  2205. xx -= 1
  2206. elif direction == self.NE:
  2207. yy += 1
  2208. xx += 1
  2209. elif direction == self.SW:
  2210. yy -= 1
  2211. xx -= 1
  2212. elif direction == self.SE:
  2213. yy -= 1
  2214. xx += 1
  2215. return xx,yy
  2216. terrainMap = TerrainMap()
  2217. ##############################################################################
  2218. ## Seed filler class
  2219. ##############################################################################
  2220. class Areamap :
  2221. def __init__(self,width,height):
  2222. self.mapWidth = width
  2223. self.mapHeight = height
  2224. self.areaMap = array('i')
  2225. #initialize map with zeros
  2226. for i in range(0,self.mapHeight*self.mapWidth):
  2227. self.areaMap.append(0)
  2228. return
  2229. def findImpassableAreas(self):
  2230. # self.areaSizes = array('i')
  2231. ## starttime = time.clock()
  2232. #make sure map is erased in case it is used multiple times
  2233. for i in range(0,self.mapHeight*self.mapWidth):
  2234. self.areaMap[i] = 0
  2235. # for i in range(0,1):
  2236. for i in range(0,self.mapHeight*self.mapWidth):
  2237. if plotMap.plotMap[i] == plotMap.OCEAN: #not assigned to an area yet
  2238. areaSize = self.fillArea(i,1)
  2239. ## endtime = time.clock()
  2240. ## elapsed = endtime - starttime
  2241. ## print "defineAreas time ="
  2242. ## print elapsed
  2243. ## print
  2244. return
  2245. def findChokePointAreas(self):
  2246. gc = CyGlobalContext()
  2247. gameMap = CyMap()
  2248. #fill water and peaks with non-zero value
  2249. for i in range(0,self.mapHeight*self.mapWidth):
  2250. gamePlot = gameMap.plotByIndex(i)
  2251. if gamePlot.isWater():
  2252. self.areaMap[i] = -1
  2253. elif gamePlot.isImpassable():
  2254. self.areaMap[i] = -3
  2255. self.areaList = list()
  2256. self.areaList.append(-1)#placeholder to avoid using a zero index
  2257. areaID = 0
  2258. for i in range(0,self.mapHeight*self.mapWidth):
  2259. if self.areaMap[i] == 0:
  2260. areaID += 1
  2261. areaSize = self.fillArea(i,areaID)
  2262. # print "areaID = %(id)d, size = %(s)d" % {"id":areaID,"s":areaSize}
  2263. self.areaList.append(areaSize)
  2264. def fillArea(self,index,areaID):
  2265. #first divide index into x and y
  2266. y = index/self.mapWidth
  2267. x = index%self.mapWidth
  2268. #We check 8 neigbors for land,but 4 for water. This is because
  2269. #the game connects land squares diagonally across water, but
  2270. #water squares are not passable diagonally across land
  2271. self.segStack = list()
  2272. self.size = 0
  2273. #place seed on stack for both directions
  2274. seg = LineSegment(y,x,x,1)
  2275. self.segStack.append(seg)
  2276. seg = LineSegment(y+1,x,x,-1)
  2277. self.segStack.append(seg)
  2278. while(len(self.segStack) > 0):
  2279. seg = self.segStack.pop()
  2280. self.scanAndFillLine(seg,areaID)
  2281. return self.size
  2282. def scanAndFillLine(self,seg,areaID):
  2283. #check for y + dy being off map
  2284. i = GetIndex(seg.xLeft,seg.y + seg.dy)
  2285. if i < 0:
  2286. ## print "scanLine off map ignoring",str(seg)
  2287. return
  2288. debugReport = False
  2289. ## if (seg.y < 8 and seg.y > 4) or (seg.y < 70 and seg.y > 64):
  2290. ## if (areaID == 4):
  2291. ## debugReport = True
  2292. #landOffset = 1 for 8 connected neighbors, 0 for 4 connected neighbors
  2293. landOffset = 1
  2294. lineFound = False
  2295. #first scan and fill any left overhang
  2296. if debugReport:
  2297. print ""
  2298. print str(seg)
  2299. print "Going left"
  2300. for xLeftExtreme in range(seg.xLeft - landOffset,-1 ,-1):
  2301. i = GetIndex(xLeftExtreme,seg.y + seg.dy)
  2302. if debugReport:
  2303. print "xLeftExtreme = %(xl)4d" % {'xl':xLeftExtreme}
  2304. if self.areaMap[i] == 0 and plotMap.plotMap[i] != plotMap.PEAK:
  2305. self.areaMap[i] = areaID
  2306. self.size += 1
  2307. lineFound = True
  2308. else:
  2309. #if no line was found, then xLeftExtreme is fine, but if
  2310. #a line was found going left, then we need to increment
  2311. #xLeftExtreme to represent the inclusive end of the line
  2312. if lineFound:
  2313. xLeftExtreme += 1
  2314. break
  2315. if debugReport:
  2316. print "xLeftExtreme finally = %(xl)4d" % {'xl':xLeftExtreme}
  2317. print "Going Right"
  2318. #now scan right to find extreme right, place each found segment on stack
  2319. # xRightExtreme = seg.xLeft - landOffset #needed sometimes? one time it was not initialized before use.
  2320. xRightExtreme = seg.xLeft #needed sometimes? one time it was not initialized before use.
  2321. for xRightExtreme in range(seg.xLeft,self.mapWidth,1):
  2322. if debugReport:
  2323. print "xRightExtreme = %(xr)4d" % {'xr':xRightExtreme}
  2324. i = GetIndex(xRightExtreme,seg.y + seg.dy)
  2325. if self.areaMap[i] == 0 and plotMap.plotMap[i] != plotMap.PEAK:
  2326. self.areaMap[i] = areaID
  2327. self.size += 1
  2328. if lineFound == False:
  2329. lineFound = True
  2330. xLeftExtreme = xRightExtreme #starting new line
  2331. if debugReport:
  2332. print "starting new line at xLeftExtreme= %(xl)4d" % {'xl':xLeftExtreme}
  2333. elif lineFound == True: #found the right end of a line segment!
  2334. lineFound = False
  2335. #put same direction on stack
  2336. newSeg = LineSegment(seg.y + seg.dy,xLeftExtreme,xRightExtreme - 1,seg.dy)
  2337. self.segStack.append(newSeg)
  2338. if debugReport:
  2339. print "same direction to stack",str(newSeg)
  2340. #determine if we must put reverse direction on stack
  2341. if xLeftExtreme < seg.xLeft or xRightExtreme >= seg.xRight:
  2342. #out of shadow so put reverse direction on stack also
  2343. newSeg = LineSegment(seg.y + seg.dy,xLeftExtreme,xRightExtreme - 1,-seg.dy)
  2344. self.segStack.append(newSeg)
  2345. if debugReport:
  2346. print "opposite direction to stack",str(newSeg)
  2347. if xRightExtreme >= seg.xRight + landOffset:
  2348. if debugReport:
  2349. print "finished with line"
  2350. break; #past the end of the parent line and this line ends
  2351. elif lineFound == False and xRightExtreme >= seg.xRight + landOffset:
  2352. if debugReport:
  2353. print "no additional lines found"
  2354. break; #past the end of the parent line and no line found
  2355. else:
  2356. continue #keep looking for more line segments
  2357. if lineFound == True: #still a line needing to be put on stack
  2358. if debugReport:
  2359. print "still needing to stack some segs"
  2360. lineFound = False
  2361. #put same direction on stack
  2362. newSeg = LineSegment(seg.y + seg.dy,xLeftExtreme,xRightExtreme - 1,seg.dy)
  2363. self.segStack.append(newSeg)
  2364. if debugReport:
  2365. print str(newSeg)
  2366. #determine if we must put reverse direction on stack
  2367. if xLeftExtreme < seg.xLeft or xRightExtreme - 1 > seg.xRight:
  2368. #out of shadow so put reverse direction on stack also
  2369. newSeg = LineSegment(seg.y + seg.dy,xLeftExtreme,xRightExtreme - 1,-seg.dy)
  2370. self.segStack.append(newSeg)
  2371. if debugReport:
  2372. print str(newSeg)
  2373. return
  2374. #for debugging
  2375. def PrintAreaMap(self):
  2376. print "Area Map"
  2377. for y in range(self.mapHeight - 1,-1,-1):
  2378. lineString = ""
  2379. for x in range(self.mapWidth):
  2380. mapLoc = self.areaMap[GetIndex(x,y)]
  2381. if mapLoc > 0:
  2382. if mapLoc + 34 > 127:
  2383. mapLoc = 127 - 34
  2384. lineString += chr(mapLoc + 34)
  2385. ## if self.areaList[mapLoc] > ChokePointAreaSize:
  2386. ## lineString += "*"
  2387. ## else:
  2388. ## lineString += "+"
  2389. elif mapLoc == 0:
  2390. lineString += "!"
  2391. elif mapLoc == -1:
  2392. lineString += "."
  2393. elif mapLoc == -2:
  2394. lineString += "X"
  2395. elif mapLoc == -3:
  2396. lineString += "^"
  2397. lineString += "-" + str(y)
  2398. print lineString
  2399. lineString = " "
  2400. print lineString
  2401. return
  2402. class LineSegment :
  2403. def __init__(self,y,xLeft,xRight,dy):
  2404. self.y = y
  2405. self.xLeft = xLeft
  2406. self.xRight = xRight
  2407. self.dy = dy
  2408. def __str__ (self):
  2409. string = "y = %(y)3d, xLeft = %(xl)3d, xRight = %(xr)3d, dy = %(dy)2d" % \
  2410. {'y':self.y,'xl':self.xLeft,'xr':self.xRight,'dy':self.dy}
  2411. return string
  2412. class StartRegion :
  2413. def __init__(self,region):
  2414. self.region = region
  2415. self.differenceFromIdeal = -1.0
  2416. class StartingPlotFinder :
  2417. def __init__(self):
  2418. return
  2419. def initialize(self):
  2420. self.availableRegionList = list()
  2421. self.occupiedRegionList = list()
  2422. def assignStartingPlots(self):
  2423. gc = CyGlobalContext()
  2424. gameMap = CyMap()
  2425. #Shuffle players so the same player doesn't always get the first pick.
  2426. playerList = list()
  2427. for plrCheckLoop in range(gc.getMAX_CIV_PLAYERS()):
  2428. if CyGlobalContext().getPlayer(plrCheckLoop).isEverAlive():
  2429. playerList.append(plrCheckLoop)
  2430. playerList = ShuffleList(playerList)
  2431. for region in regMap.regionList:
  2432. if not region.isWater:
  2433. startRegion = StartRegion(region)
  2434. self.availableRegionList.append(startRegion)
  2435. civPreferenceList = GetCivPreferences()
  2436. for playerIndex in playerList:
  2437. player = gc.getPlayer(playerIndex)
  2438. player.AI_updateFoundValues(True)
  2439. civType = player.getCivilizationType()
  2440. civInfo = gc.getCivilizationInfo(civType)
  2441. print "Civ = %(c)s" % {"c":civInfo.getType()}
  2442. civPref = self.getCivPreference(civPreferenceList,civType)
  2443. bestRegion = self.getBestStartRegion(self.availableRegionList,self.occupiedRegionList,civPref)
  2444. startPlot = self.getStartPlotInRegion(bestRegion.region,player,civPref)
  2445. DeleteFromList(self.availableRegionList,bestRegion)
  2446. self.occupiedRegionList.append(bestRegion)
  2447. player.setStartingPlot(startPlot,True)
  2448. return
  2449. def getStartPlotInRegion(self,region,player,civPref):
  2450. gc = CyGlobalContext()
  2451. gameMap = CyMap()
  2452. bestValue = 0
  2453. bestPlot = None
  2454. for plot in region.plotList:
  2455. startPlot = gameMap.plot(plot.x,plot.y)
  2456. if civPref.needCoastalStart and not isCoast(startPlot):
  2457. continue
  2458. if startPlot.isPeak() == True:
  2459. continue
  2460. value = startPlot.getFoundValue(player.getID())
  2461. if value > bestValue:
  2462. bestValue = value
  2463. bestPlot = startPlot
  2464. if bestPlot == None:
  2465. raise ValueError, "best plot in region is null"
  2466. return bestPlot
  2467. def getBestStartRegion(self,availableRegionList,occupiedRegionList,civPref):
  2468. bestRegionList = list()
  2469. for startRegion in availableRegionList:
  2470. #first make sure region has a water gateRegion if coastal start
  2471. #is desired
  2472. if civPref.needCoastalStart:
  2473. gateRegion = regMap.getRegionByID(startRegion.region.gateRegion)
  2474. if not gateRegion.isWater:
  2475. continue
  2476. if len(startRegion.region.plotList) < mc.MinRegionSizeStart:
  2477. continue
  2478. bestRegionList.append(startRegion)
  2479. for startRegion in bestRegionList:
  2480. normalizedAlt = startRegion.region.altitude/regMap.highestRegionAltitude
  2481. altitudeDiff = abs(normalizedAlt - civPref.idealAltitude)
  2482. moistureDiff = abs(startRegion.region.moisture - civPref.idealMoisture)
  2483. maxDistance = GetDistance(0,0,mapSize.MapWidth - 1,mapSize.MapHeight - 1)
  2484. distanceToNearest = self.getDistToNearestOccRegion(occupiedRegionList,startRegion)
  2485. distanceFactor = 1.0 - (distanceToNearest/maxDistance)
  2486. weightedAverageDiff = ((civPref.altitudeWeight * altitudeDiff) + (distanceFactor * civPref.distanceWeight) + moistureDiff)/(civPref.altitudeWeight + civPref.distanceWeight + 1)
  2487. ## print "regionID = %(r)d, altitudeDiff= %(ad)f, moistureDiff= %(md)f, altitudeWeight= %(aw)f, weightedAverageDiff= %(wd)f" % \
  2488. ## {"r":startRegion.region.ID,"ad":altitudeDiff,"md":moistureDiff,"aw":civPref.altitudeWeight,"wd":weightedAverageDiff}
  2489. startRegion.differenceFromIdeal = weightedAverageDiff
  2490. bestRegionList.sort(lambda x,y:cmp(x.differenceFromIdeal,y.differenceFromIdeal))
  2491. startRegion = bestRegionList[0]
  2492. print "chosen regionID = %(r)d" % {"r":startRegion.region.ID}
  2493. return startRegion
  2494. def getDistToNearestOccRegion(self,occupiedRegionList,startRegion):
  2495. minDistance = GetDistance(0,0,mapSize.MapWidth - 1,mapSize.MapHeight - 1)
  2496. for occRegion in occupiedRegionList:
  2497. startGatePlot = startRegion.region.gatePlot
  2498. if startGatePlot == None:
  2499. continue
  2500. occGatePlot = occRegion.region.gatePlot
  2501. distance = GetDistance(startGatePlot.x,startGatePlot.y,occGatePlot.x,occGatePlot.y)
  2502. minDistance = min(distance,minDistance)
  2503. return minDistance
  2504. def getCivPreference(self,civPreferenceList,civType):
  2505. for civPref in civPreferenceList:
  2506. if civPref.civ == civType:
  2507. return civPref
  2508. #None defined so let's make a generic one
  2509. civPref = CivPreference(civType)
  2510. return civPref
  2511. def replaceUniqueImprovements(self):
  2512. gc = CyGlobalContext()
  2513. gameMap = CyMap()
  2514. impPrefList = GetImprovementPreferences()
  2515. availableRegionList = list()
  2516. occupiedRegionList = list()
  2517. for region in regMap.regionList:
  2518. startRegion = StartRegion(region)
  2519. availableRegionList.append(startRegion)
  2520. for y in range(mapSize.MapHeight):
  2521. for x in range(mapSize.MapWidth):
  2522. plot = gameMap.plot(x,y)
  2523. impType = plot.getImprovementType()
  2524. impInfo = gc.getImprovementInfo(impType)
  2525. if impInfo == None:
  2526. continue
  2527. print "Found %(i)s" % {"i":impInfo.getType()}
  2528. impPref = None
  2529. #Find impType in preference list
  2530. for foundImpPref in impPrefList:
  2531. if foundImpPref.improvement == impType:
  2532. impPref = foundImpPref
  2533. break
  2534. if impPref == None:
  2535. continue
  2536. impInfo = gc.getImprovementInfo(impType)
  2537. print "Removing %(i)s at %(x)d, %(y)d" % {"i":impInfo.getType(),"x":x,"y":y}
  2538. plot.setImprovementType(ImprovementTypes.NO_IMPROVEMENT)
  2539. ## numUnits = plot.getNumUnits()
  2540. ## unitList = list()
  2541. ## for n in range(numUnits):
  2542. ## unit = plot.getUnit(n)
  2543. ## unitList.append(unit)
  2544. plot.setBonusType(BonusTypes.NO_BONUS)
  2545. # FF: Changed by Jean Elcard 11/20/2008
  2546. '''
  2547. bestRegion = self.getBestImprovementRegion(availableRegionList,occupiedRegionList,impPref)
  2548. DeleteFromList(availableRegionList,bestRegion)
  2549. occupiedRegionList.append(bestRegion)
  2550. bestPlot = self.getBestImpPlotInRegion(bestRegion.region,impPref)
  2551. DeleteFromList(impPrefList,impPref)
  2552. print "Adding %(i)s at %(x)d, %(y)d" % {"i":impInfo.getType(),"x":bestPlot.getX(),"y":bestPlot.getY()}
  2553. bestPlot.setImprovementType(impType)
  2554. '''
  2555. if len(availableRegionList) > 0:
  2556. bestRegion = self.getBestImprovementRegion(availableRegionList,occupiedRegionList,impPref)
  2557. if bestRegion:
  2558. # if not CyGame().isOption(GameOptionTypes.GAMEOPTION_ALL_UNIQUE_FEATURES):
  2559. DeleteFromList(availableRegionList,bestRegion)
  2560. occupiedRegionList.append(bestRegion)
  2561. bestPlot = self.getBestImpPlotInRegion(bestRegion.region,impPref)
  2562. DeleteFromList(impPrefList,impPref)
  2563. print "Adding %(i)s at %(x)d, %(y)d" % {"i":impInfo.getType(),"x":bestPlot.getX(),"y":bestPlot.getY()}
  2564. bestPlot.setImprovementType(impType)
  2565. else: print "FF: No suitable region found for %(i)s." % {"i":impInfo.getType()}
  2566. else: print "FF: Not enough regions to add %(i)s." % {"i":impInfo.getType()}
  2567. # FF: End Change
  2568. ## for n in range(numUnits):
  2569. ## unit = unitList[n]
  2570. ## unit.setXY(bestPlot.getX(),bestPlot.getY(),False,True,False)
  2571. def getBestImprovementRegion(self,availableRegionList,occupiedRegionList,impPref):
  2572. bestRegionList = list()
  2573. for startRegion in availableRegionList:
  2574. #first make sure region has a water gateRegion if coastal plot
  2575. #is desired
  2576. if impPref.needCoast:
  2577. gateRegion = regMap.getRegionByID(startRegion.region.gateRegion)
  2578. if not gateRegion.isWater:
  2579. continue
  2580. if impPref.needWater:
  2581. if not startRegion.region.isWater:
  2582. continue
  2583. if startRegion.region.isWater:
  2584. continue #water regions not supported right now
  2585. if len(startRegion.region.plotList) < mc.MinRegionSizeTower:
  2586. continue
  2587. if impPref.needChoke:
  2588. if self.findChokePoint(startRegion.region) == None:
  2589. continue
  2590. bestRegionList.append(startRegion)
  2591. # FF: Added by Jean Elcard 11/20/2008
  2592. if len(bestRegionList) == 0:
  2593. return None
  2594. # FF: End Add
  2595. for startRegion in bestRegionList:
  2596. normalizedAlt = startRegion.region.altitude/regMap.highestRegionAltitude
  2597. altitudeDiff = abs(normalizedAlt - impPref.idealAltitude)
  2598. moistureDiff = abs(startRegion.region.moisture - impPref.idealMoisture)
  2599. maxDistance = GetDistance(0,0,mapSize.MapWidth - 1,mapSize.MapHeight - 1)
  2600. distanceToNearest = self.getDistToNearestOccRegion(occupiedRegionList,startRegion)
  2601. distanceFactor = 1.0 - (distanceToNearest/maxDistance)
  2602. weightedAverageDiff = ((impPref.altitudeWeight * altitudeDiff) + distanceFactor + (moistureDiff * impPref.moistureWeight))/(impPref.altitudeWeight + impPref.moistureWeight + 1)
  2603. print "regionID = %(r)d, altitudeDiff= %(ad)f, moistureDiff= %(md)f, altitudeWeight= %(aw)f, weightedAverageDiff= %(wd)f" % \
  2604. {"r":startRegion.region.ID,"ad":altitudeDiff,"md":moistureDiff,"aw":impPref.altitudeWeight,"wd":weightedAverageDiff}
  2605. startRegion.differenceFromIdeal = weightedAverageDiff
  2606. bestRegionList.sort(lambda x,y:cmp(x.differenceFromIdeal,y.differenceFromIdeal))
  2607. startRegion = bestRegionList[0]
  2608. print "chosen regionID = %(r)d" % {"r":startRegion.region.ID}
  2609. return startRegion
  2610. def getBestImpPlotInRegion(self,region,impPref):
  2611. gc = CyGlobalContext()
  2612. gameMap = CyMap()
  2613. midPoint = region.getCenter()
  2614. ## print "midPoint.x= %(mx)d, midPoint.y= %(my)d" % {"mx":midPoint.x,"my":midPoint.y}
  2615. minDistance = 100.0
  2616. bestPlot = gameMap.plot(midPoint.x,midPoint.y)
  2617. region.plotList = ShuffleList(region.plotList)
  2618. for plot in region.plotList:
  2619. i = GetIndex(plot.x,plot.y)
  2620. gamePlot = gameMap.plot(plot.x,plot.y)
  2621. print "gamePlot = %(x)d,%(y)d" % {"x":plot.x,"y":plot.y}
  2622. if gamePlot.getBonusType(TeamTypes.NO_TEAM) != BonusTypes.NO_BONUS:
  2623. continue
  2624. # FF: Added by Jean Elcard 11/20/2008
  2625. if gamePlot.getImprovementType() != ImprovementTypes.NO_IMPROVEMENT:
  2626. continue
  2627. # FF: End Add
  2628. if gamePlot.isPeak() == True and impPref.needChoke == False:
  2629. print "rejected for peak"
  2630. continue
  2631. if impPref.needHill and plotMap.plotMap[i] != plotMap.HILLS:
  2632. print "rejected for not hill"
  2633. continue
  2634. if impPref.needFlat and plotMap.plotMap[i] != plotMap.LAND:
  2635. print "rejected for not flat"
  2636. continue
  2637. if impPref.needCoast and not isCoast(gamePlot):
  2638. continue
  2639. if impPref.favoredTerrain != TerrainTypes.NO_TERRAIN \
  2640. and gamePlot.getTerrainType() != impPref.favoredTerrain:
  2641. print "rejected for not favored terrain"
  2642. continue
  2643. if impPref.needChoke:
  2644. chokePlot = self.findChokePoint(region)
  2645. if (plot.x >= chokePlot.getX() - 1 and plot.x <= chokePlot.getX() + 1 \
  2646. and plot.y >= chokePlot.getY() - 1 and plot.y <= chokePlot.getY() + 1 \
  2647. and gamePlot.isPeak()):
  2648. print "Found choke"
  2649. #place bait
  2650. reagents = GetInfoType("BONUS_REAGENTS")
  2651. if reagents != -1:
  2652. for direction in range(1,9,1):
  2653. xx,yy = plotMap.getXYFromDirection(plot.x,plot.y,direction)
  2654. baitPlot = gameMap.plot(xx,yy)
  2655. forest = mst.efForest
  2656. if forest != -1 and baitPlot.getFeatureType() == forest:
  2657. baitPlot.setFeatureType(FeatureTypes.NO_FEATURE,0)
  2658. if baitPlot.canHaveBonus(reagents,True):
  2659. baitPlot.setBonusType(reagents)
  2660. break
  2661. else:
  2662. print "rejected not next to choke=%(x)d,%(y)d or not peak" % {"x":chokePlot.getX(),"y":chokePlot.getY()}
  2663. continue
  2664. bestPlot = gameMap.plot(plot.x,plot.y)
  2665. break
  2666. return bestPlot
  2667. def collectAllWatchtowers(self):
  2668. gc = CyGlobalContext()
  2669. gameMap = CyMap()
  2670. count = 0
  2671. for y in range(mapSize.MapHeight):
  2672. for x in range(mapSize.MapWidth):
  2673. plot = gameMap.plot(x,y)
  2674. impType = plot.getImprovementType()
  2675. if impType == GetInfoType("IMPROVEMENT_TOWER"):
  2676. count += 1
  2677. plot.setImprovementType(ImprovementTypes.NO_IMPROVEMENT)
  2678. print "razed %(t)d watchtowers" % {"t":count}
  2679. return count
  2680. def replaceWatchtowers(self,count):
  2681. ## regMap.PrintRegionMap(False)
  2682. gc = CyGlobalContext()
  2683. gameMap = CyMap()
  2684. towersPlacedAtChoke = 0
  2685. towersPlacedInMiddle = 0
  2686. self.createChokePointList()
  2687. for region in regMap.regionList:
  2688. if region.isWater:
  2689. continue
  2690. if len(region.plotList) < mc.MinRegionSizeTower:
  2691. continue
  2692. if PRand.randint(0,3) == 0:
  2693. continue #not all regions should have a tower
  2694. ## print "placing towers in region %(r)d" % {"r":region.ID}
  2695. if PRand.randint(0,1) == 0:
  2696. chokePoint = self.findChokePoint(region)
  2697. badNeighbor = False
  2698. if chokePoint != None:
  2699. for direction in range(1,9,1):
  2700. x,y = plotMap.getXYFromDirection(chokePoint.getX(),chokePoint.getY(),direction)
  2701. nPlot = gameMap.plot(x,y)
  2702. if nPlot.getImprovementType() != ImprovementTypes.NO_IMPROVEMENT:
  2703. badNeighbor = True
  2704. if chokePoint != None and not badNeighbor:
  2705. chokePoint.setImprovementType(GetInfoType("IMPROVEMENT_TOWER"))
  2706. towersPlacedAtChoke += 1
  2707. continue #regions should not have a choke tower and mid tower or else they might appear together
  2708. #If a chokepoint is not found or if mid tower is randomly selected,
  2709. #place tower in the middle of a region
  2710. midPoint = region.getCenter()
  2711. ## print "midPoint.x= %(mx)d, midPoint.y= %(my)d" % {"mx":midPoint.x,"my":midPoint.y}
  2712. minDistance = 100.0
  2713. bestPlot = None
  2714. for plot in region.plotList:
  2715. i = GetIndex(plot.x,plot.y)
  2716. gamePlot = gameMap.plot(plot.x,plot.y)
  2717. if gamePlot.getBonusType(TeamTypes.NO_TEAM) != BonusTypes.NO_BONUS:
  2718. continue
  2719. if plotMap.plotMap[i] == plotMap.HILLS:
  2720. distance = GetDistance(plot.x,plot.y,midPoint.x,midPoint.y)
  2721. if minDistance > distance:
  2722. bestPlot = plot
  2723. minDistance = distance
  2724. if bestPlot != None:
  2725. midHill = gameMap.plot(bestPlot.x,bestPlot.y)
  2726. midHill.setImprovementType(GetInfoType("IMPROVEMENT_TOWER"))
  2727. towersPlacedInMiddle += 1
  2728. print "towersPlacedAtChoke= %(c)d, towersPlacedInMiddle= %(m)d, total= %(t)d" % \
  2729. {"c":towersPlacedAtChoke,"m":towersPlacedInMiddle,"t":towersPlacedAtChoke + towersPlacedInMiddle}
  2730. def createChokePointList(self):
  2731. gc = CyGlobalContext()
  2732. gameMap = CyMap()
  2733. areaMap = Areamap(mapSize.MapWidth,mapSize.MapHeight)
  2734. possibleChokeList = list()
  2735. likelyChokeList = list()
  2736. self.chokePointList = list()
  2737. chokeAreaList = list()
  2738. #First compile a list of local chokepoints
  2739. for y in range(mapSize.MapHeight):
  2740. for x in range(mapSize.MapWidth):
  2741. i = GetIndex(x,y)
  2742. if self.isPossibleChokePoint(x,y):
  2743. areaMap.areaMap[i] = -2
  2744. possibleChokeList.append(ChokePoint(x,y))
  2745. #Then eliminate chokes that don't connect significant areas
  2746. areaMap.findChokePointAreas()
  2747. for i in range(len(areaMap.areaList)):
  2748. chokeAreaList.append(ChokeArea(i,areaMap.areaList[i]))
  2749. for possibleChoke in possibleChokeList:
  2750. self.findChokeNeighbors(possibleChoke,areaMap,chokeAreaList,possibleChokeList)
  2751. for possibleChoke in possibleChokeList:
  2752. for area in possibleChoke.neighborAreaList:
  2753. if area.size > mc.ChokePointAreaSize:
  2754. chokesCheckedList = list()
  2755. ## print "Starting area search through %(p)s ----------------------------------------------------------" % \
  2756. ## {"p":str(possibleChoke)}
  2757. if self.canFindAdditionalAreaThroughChokes(possibleChoke,area,chokesCheckedList,True):
  2758. likelyChokeList.append(possibleChoke)#upgrade!
  2759. ## print "choke %(x)d,%(y)d is valid \n------------------------------------------------------\n" \
  2760. ## % {"x":possibleChoke.x,"y":possibleChoke.y}
  2761. ## else:
  2762. ## print "choke %(x)d,%(y)d is NOT valid \n------------------------------------------------------\n" \
  2763. ## % {"x":possibleChoke.x,"y":possibleChoke.y}
  2764. break
  2765. ## areaMap.PrintAreaMap()
  2766. ## for chokePoint in likelyChokeList:
  2767. ## print "Likely chokepoint at %(x)d, %(y)d" % {"x":chokePoint.x,"y":chokePoint.y}
  2768. #Now you have a list of good chokepoints, but some areas may have so many
  2769. #choke points that none of them are useful. Now we block the choke points
  2770. #and test the walk-around distance to see if this choke point is useful
  2771. for chokePoint in likelyChokeList:
  2772. if self.isConfirmedChokePoint(chokePoint):
  2773. print "Confirmed chokepoint at %(c)s" % {"c":str(chokePoint)}
  2774. self.chokePointList.append(chokePoint)
  2775. else:
  2776. print "Rejected chokepoint at %(x)d, %(y)d" % {"x":chokePoint.x,"y":chokePoint.y}
  2777. return
  2778. def isConfirmedChokePoint(self,choke):
  2779. gc = CyGlobalContext()
  2780. gameMap = CyMap()
  2781. gamePlot = gameMap.plot(choke.x,choke.y)
  2782. #remember old plot type so we can replace
  2783. oldPlotType = gamePlot.getPlotType()
  2784. #change plot type to peak to block path
  2785. gamePlot.setPlotType(PlotTypes.PLOT_PEAK,True,True)
  2786. for inX,inY in choke.gateList:
  2787. for outX,outY in choke.gateList:
  2788. if outX == inX and outY == inY:
  2789. continue
  2790. gameMap.resetPathDistance()
  2791. inPlot = gameMap.plot(inX,inY)
  2792. outPlot = gameMap.plot(outX,outY)
  2793. distance = gameMap.calculatePathDistance(inPlot,outPlot)
  2794. ## print "distance from %(ix)d,%(iy)d to %(ox)d,%(oy)d = %(d)d" % \
  2795. ## {"ix":inX,"iy":inY,"ox":outX,"oy":outY,"d":distance}
  2796. if distance >= mc.ChokePointWalkAroundDistance or distance == -1:
  2797. gamePlot.setPlotType(oldPlotType,True,True)
  2798. return True
  2799. gamePlot.setPlotType(oldPlotType,True,True)
  2800. return False
  2801. def canFindAdditionalAreaThroughChokes(self,possibleChoke,origionalArea,chokesCheckedList,bTopLayer):
  2802. #First try to find a large area that is not the origional area
  2803. twoAreasFound = False
  2804. returnValue = False
  2805. for area in possibleChoke.neighborAreaList:
  2806. if bTopLayer == False and area == origionalArea:
  2807. ## print "This secondary choke touches origional area and must be declared a dead end."
  2808. return False
  2809. elif area != origionalArea and area.size > mc.ChokePointAreaSize:
  2810. twoAreasFound = True
  2811. if twoAreasFound:
  2812. ## print "Chokepoint %(c)s leads to second large area" % {"c":str(possibleChoke)}
  2813. returnValue = True
  2814. #These coordinates are checked and can not be checked again or else endless loop possible
  2815. chokesCheckedList.append(possibleChoke)
  2816. largeAreaFound = False
  2817. #Now loop through neighbor choke points and recurse this function if they aren't
  2818. #in checked list
  2819. for neighborChoke in possibleChoke.neighborChokeList:
  2820. alreadyChecked = False
  2821. for checkedChoke in chokesCheckedList:
  2822. if checkedChoke == neighborChoke:
  2823. alreadyChecked = True
  2824. if not alreadyChecked:
  2825. ## print "possibleChoke(%(x)d,%(y)d) searching through %(n)s" % \
  2826. ## {"x":possibleChoke.x,"y":possibleChoke.y,"n":str(neighborChoke)}
  2827. largeAreaFound = self.canFindAdditionalAreaThroughChokes(neighborChoke,origionalArea,chokesCheckedList,False)
  2828. if largeAreaFound == True:
  2829. ## print "Found second area through neighbor chokepoint"
  2830. if bTopLayer:
  2831. possibleChoke.gateList.append((neighborChoke.x,neighborChoke.y))#for final path check
  2832. returnValue = True
  2833. #Now loop through small areas neighbor choke points
  2834. for neighborArea in possibleChoke.neighborAreaList:
  2835. if area != origionalArea:
  2836. ## print "possibleChoke(%(x)d,%(y)d) searching through %(n)s" % \
  2837. ## {"x":possibleChoke.x,"y":possibleChoke.y,"n":str(area)}
  2838. for neighborChoke in neighborArea.neighborChokeList:
  2839. alreadyChecked = False
  2840. for checkedChoke in chokesCheckedList:
  2841. if checkedChoke == neighborChoke:
  2842. alreadyChecked = True
  2843. if not alreadyChecked:
  2844. ## print "possibleChoke(%(x)d,%(y)d) searching through %(n)s which is through area=%(a)d,%(c)s" % \
  2845. ## {"x":possibleChoke.x,"y":possibleChoke.y,"n":str(neighborChoke),"a":area.ID,"c":chr(area.ID + 34)}
  2846. largeAreaFound = self.canFindAdditionalAreaThroughChokes(neighborChoke,origionalArea,chokesCheckedList,False)
  2847. if largeAreaFound == True:
  2848. ## print "Found second area through neighbor area and chokepoint"
  2849. if bTopLayer:
  2850. possibleChoke.gateList.append((neighborChoke.x,neighborChoke.y))#for final path check
  2851. returnValue = True
  2852. ## if returnValue == False:
  2853. ## print "no second area found through possibleChoke(%(x)d,%(y)d)" % \
  2854. ## {"x":possibleChoke.x,"y":possibleChoke.y}
  2855. return returnValue
  2856. def findChokeNeighbors(self,possibleChoke,areaMap,chokeAreaList,possibleChokeList):
  2857. for direction in range(1,9,1):
  2858. xx,yy = plotMap.getXYFromDirection(possibleChoke.x,possibleChoke.y,direction)
  2859. i = GetIndex(xx,yy)
  2860. if i == -1:
  2861. continue
  2862. if areaMap.areaMap[i] == -2:
  2863. for neighborChoke in possibleChokeList:
  2864. if neighborChoke.x == xx and neighborChoke.y == yy:
  2865. possibleChoke.neighborChokeList.append(neighborChoke)
  2866. elif areaMap.areaMap[i] > 0:
  2867. #make sure it's not in list already before adding it
  2868. alreadyInList = False
  2869. for area in possibleChoke.neighborAreaList:
  2870. if area.ID == areaMap.areaMap[i]:
  2871. alreadyInList = True
  2872. if alreadyInList == False:
  2873. #add area to neighbor list and also add this choke to areas neighbor list
  2874. for area in chokeAreaList:
  2875. if area.ID == areaMap.areaMap[i]:
  2876. possibleChoke.neighborAreaList.append(area)
  2877. area.neighborChokeList.append(possibleChoke)
  2878. if area.size > mc.ChokePointAreaSize:
  2879. possibleChoke.gateList.append((xx,yy))#gateList is for final path check
  2880. return
  2881. def isPossibleChokePoint(self,x,y):
  2882. gc = CyGlobalContext()
  2883. gameMap = CyMap()
  2884. gamePlot = gameMap.plot(x,y)
  2885. i = GetIndex(x,y)
  2886. if gamePlot.isWater() or gamePlot.isImpassable():
  2887. return False
  2888. if gamePlot.getBonusType(TeamTypes.NO_TEAM) != BonusTypes.NO_BONUS:
  2889. return False
  2890. #First check cardinal directions
  2891. direction = plotMap.W
  2892. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2893. passable = self.isPassableLand(xx,yy)
  2894. oppDir = plotMap.getOppositeDirection(direction)
  2895. xxx,yyy = plotMap.getXYFromDirection(x,y,oppDir)
  2896. if passable == self.isPassableLand(xxx,yyy):
  2897. direction = plotMap.N
  2898. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2899. oppDir = plotMap.getOppositeDirection(direction)
  2900. xxx,yyy = plotMap.getXYFromDirection(x,y,oppDir)
  2901. if passable != self.isPassableLand(xx,yy) and passable != self.isPassableLand(xxx,yyy):
  2902. # print "choke at %(x)d,%(y)d is opposites" % {"x":x,"y":y}
  2903. return True #Definately a possible choke
  2904. #No choke yet, try diagonal chokes
  2905. direction = plotMap.NW
  2906. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2907. if self.isPassableLand(xx,yy):
  2908. direction = plotMap.N
  2909. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2910. direction = plotMap.W
  2911. xxx,yyy = plotMap.getXYFromDirection(x,y,direction)
  2912. if self.isPassableLand(xx,yy) == False and self.isPassableLand(xxx,yyy) == False:
  2913. # print "choke at %(x)d,%(y)d is NW diagonal" % {"x":x,"y":y}
  2914. return True #choke
  2915. direction = plotMap.NE
  2916. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2917. if self.isPassableLand(xx,yy):
  2918. direction = plotMap.N
  2919. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2920. direction = plotMap.E
  2921. xxx,yyy = plotMap.getXYFromDirection(x,y,direction)
  2922. if self.isPassableLand(xx,yy) == False and self.isPassableLand(xxx,yyy) == False:
  2923. # print "choke at %(x)d,%(y)d is NE diagonal" % {"x":x,"y":y}
  2924. return True #choke
  2925. direction = plotMap.SW
  2926. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2927. if self.isPassableLand(xx,yy):
  2928. direction = plotMap.S
  2929. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2930. direction = plotMap.W
  2931. xxx,yyy = plotMap.getXYFromDirection(x,y,direction)
  2932. if self.isPassableLand(xx,yy) == False and self.isPassableLand(xxx,yyy) == False:
  2933. # print "choke at %(x)d,%(y)d is SW diagonal" % {"x":x,"y":y}
  2934. return True #choke
  2935. direction = plotMap.SE
  2936. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2937. if self.isPassableLand(xx,yy):
  2938. direction = plotMap.S
  2939. xx,yy = plotMap.getXYFromDirection(x,y,direction)
  2940. direction = plotMap.E
  2941. xxx,yyy = plotMap.getXYFromDirection(x,y,direction)
  2942. if self.isPassableLand(xx,yy) == False and self.isPassableLand(xxx,yyy) == False:
  2943. # print "choke at %(x)d,%(y)d is SE diagonal" % {"x":x,"y":y}
  2944. return True #choke
  2945. return False
  2946. def isPassableLand(self,x,y):
  2947. gc = CyGlobalContext()
  2948. gameMap = CyMap()
  2949. gamePlot = gameMap.plot(x,y)
  2950. i = GetIndex(x,y)
  2951. if i == -1:
  2952. return False
  2953. if gamePlot.isWater() or gamePlot.isImpassable():
  2954. return False
  2955. return True
  2956. def findChokePoint(self,region):
  2957. gc = CyGlobalContext()
  2958. gameMap = CyMap()
  2959. for choke in self.chokePointList:
  2960. for plot in region.plotList:
  2961. if plot.x == choke.x and plot.y == choke.y:
  2962. return gameMap.plot(plot.x,plot.y)
  2963. ## for plot in region.plotList:
  2964. ## i = GetIndex(plot.x,plot.y)
  2965. ## if plotMap.plotMap[i] == plotMap.PEAK:
  2966. ## continue
  2967. ## gamePlot = gameMap.plot(plot.x,plot.y)
  2968. ## if gamePlot.getBonusType(TeamTypes.NO_TEAM) != BonusTypes.NO_BONUS:
  2969. ## continue
  2970. ## oppositePeaks = False
  2971. ## for direction in range(1,5,1):
  2972. ## xx,yy = plotMap.getXYFromDirection(plot.x,plot.y,direction)
  2973. ## ii = GetIndex(xx,yy)
  2974. ## if plotMap.plotMap[ii] == plotMap.PEAK:
  2975. ## oppDir = plotMap.getOppositeDirection(direction)
  2976. ## xxx,yyy = plotMap.getXYFromDirection(plot.x,plot.y,oppDir)
  2977. ## iii = GetIndex(xxx,yyy)
  2978. ## if plotMap.plotMap[iii] == plotMap.PEAK:
  2979. ## oppositePeaks = True
  2980. ##
  2981. ## oppositePass = False
  2982. ## for direction in range(1,5,1):
  2983. ## xx,yy = plotMap.getXYFromDirection(plot.x,plot.y,direction)
  2984. ## ii = GetIndex(xx,yy)
  2985. ## if plotMap.plotMap[ii] != plotMap.PEAK:
  2986. ## oppDir = plotMap.getOppositeDirection(direction)
  2987. ## xxx,yyy = plotMap.getXYFromDirection(plot.x,plot.y,oppDir)
  2988. ## iii = GetIndex(xxx,yyy)
  2989. ## if plotMap.plotMap[iii] != plotMap.PEAK:
  2990. ## oppositePass = True
  2991. ## if oppositePeaks and oppositePass:
  2992. ## chokePoint = gameMap.plot(plot.x,plot.y)
  2993. ## if chokePoint.isRiverSide() == True:
  2994. ## return chokePoint
  2995. return None
  2996. class ChokePoint :
  2997. def __init__(self,x,y):
  2998. self.x = x
  2999. self.y = y
  3000. self.neighborChokeList = list()
  3001. self.neighborAreaList = list()
  3002. self.gateList = list()
  3003. return
  3004. def __str__(self):
  3005. rstring = "%(x)d,%(y)d \n" % {"x":self.x,"y":self.y}
  3006. rstring += " neighborChokeList = \n"
  3007. for nChoke in self.neighborChokeList:
  3008. rstring += " %(x)d,%(y)d\n" % {"x":nChoke.x,"y":nChoke.y}
  3009. rstring += " neighborAreaList = \n"
  3010. for nArea in self.neighborAreaList:
  3011. rstring +=" ID=%(id)d, char=%(c)s, size=%(s)d \n" % {"id":nArea.ID,"c":chr(nArea.ID + 34),"s":nArea.size}
  3012. rstring += " gateList = \n"
  3013. for x,y in self.gateList:
  3014. rstring += " %(x)d,%(y)d\n" % {"x":x,"y":y}
  3015. return rstring
  3016. class ChokeArea :
  3017. def __init__(self,ID,size):
  3018. self.ID = ID
  3019. self.size = size
  3020. self.neighborChokeList = list()
  3021. def __str__(self):
  3022. rstring = "ID=%(id)d, char=%(c)s, size=%(s)d \n" % {"id":self.ID,"c":chr(self.ID + 34),"s":self.size}
  3023. rstring += " neighborChokeList = \n"
  3024. for nChoke in self.neighborChokeList:
  3025. rstring += " %(x)d,%(y)d\n" % {"x":nChoke.x,"y":nChoke.y}
  3026. return rstring
  3027. spf = StartingPlotFinder()
  3028. #######################################################################################
  3029. ## Global Functions
  3030. #######################################################################################
  3031. #This function appends an item to a list only if it is not already
  3032. #in the list
  3033. def isCoast(plot):
  3034. WaterArea = plot.waterArea()
  3035. if not WaterArea.isNone():
  3036. if not WaterArea.isLake():
  3037. return True
  3038. return False
  3039. def AppendUnique(theList,newItem):
  3040. if IsInList(theList,newItem) == False:
  3041. theList.append(newItem)
  3042. return
  3043. def IsInList(theList,newItem):
  3044. itemFound = False
  3045. for item in theList:
  3046. if item == newItem:
  3047. itemFound = True
  3048. break
  3049. return itemFound
  3050. def DeleteFromList(theList,oldItem):
  3051. for n in range(len(theList)):
  3052. if theList[n] == oldItem:
  3053. del theList[n]
  3054. break
  3055. return
  3056. def ShuffleList(theList):
  3057. preshuffle = list()
  3058. shuffled = list()
  3059. numElements = len(theList)
  3060. for i in range(numElements):
  3061. preshuffle.append(theList[i])
  3062. for i in range(numElements):
  3063. n = PRand.randint(0,len(preshuffle)-1)
  3064. shuffled.append(preshuffle[n])
  3065. del preshuffle[n]
  3066. return shuffled
  3067. def GetInfoType(string):
  3068. cgc = CyGlobalContext()
  3069. return cgc.getInfoTypeForString(string)
  3070. def GetPlotAltitude(x,y):
  3071. #calculate highest region altitude if necessary and save it for later
  3072. if regMap.highestRegionAltitude == 0:
  3073. regMap.regionList.sort(lambda n,m: cmp(n.altitude,m.altitude))
  3074. regMap.regionList.reverse()
  3075. regMap.highestRegionAltitude = regMap.regionList[0].altitude
  3076. i = GetIndex(x,y)
  3077. regionID = regMap.regionMap[i]
  3078. if regionID == -1:
  3079. return -1.0
  3080. region = regMap.getRegionByID(regionID)
  3081. ## print "GetPlotAltitude"
  3082. regionAlt = float(region.altitude + 1)/float(regMap.highestRegionAltitude + 1)
  3083. ## print "regionAlt = %(ra)f" % {"ra":regionAlt}
  3084. riverAltRange = mc.RiverAltRangeFactor * float(mc.RiverThreshold)
  3085. riverSize = GetRiverSize(x,y)
  3086. if riverSize > riverAltRange:
  3087. riverSize = riverAltRange
  3088. ## print "riverSize = %(r)f" % {"r":riverSize}
  3089. riverSubtract = riverSize * ((mc.RiverAltitudeSubtraction/riverAltRange)/float(regMap.highestRegionAltitude + 1))
  3090. ## print "riverSubtract = %(rs)f" % {"rs":riverSubtract}
  3091. altitude = regionAlt - riverSubtract
  3092. ## print "altitude = %(a)f" % {"a":altitude}
  3093. ## print ""
  3094. return altitude
  3095. def GetRiverSize(x,y):
  3096. riverAverage = 0.0
  3097. for direction in range(5,9,1):
  3098. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  3099. rxI = riverMap.getRiverIndex(rxX,rxY)
  3100. riverAverage += float(riverMap.riverMap[rxI])
  3101. riverAverage = riverAverage/4.0
  3102. return riverAverage
  3103. def IsPlotTouchingRiver(x,y):
  3104. for direction in range(5,9,1):
  3105. rxX,rxY = riverMap.rxFromPlot(x,y,direction)
  3106. rxI = riverMap.getRiverIndex(rxX,rxY)
  3107. if riverMap.riverMap[rxI] > mc.RiverThreshold:
  3108. return True
  3109. return False
  3110. def IsPlotSurroundedByOcean(x,y):
  3111. for direction in range(1,9,1):
  3112. xx,yy = regMap.getXYFromDirection(x,y,direction)
  3113. i = GetIndex(xx,yy)
  3114. if plotMap.plotMap[i] != plotMap.OCEAN:
  3115. return False
  3116. return True
  3117. def SetClimateOptions():
  3118. climate = CyMap().getClimate()
  3119. if climate == GetInfoType("CLIMATE_ARID"):
  3120. mc.JungleThreshold = .98
  3121. mc.PlainsThreshold = .80
  3122. mc.DesertThreshold = .70
  3123. elif climate == GetInfoType("CLIMATE_TROPICAL"):
  3124. mc.JungleThreshold = .50
  3125. mc.PlainsThreshold = .35
  3126. mc.DesertThreshold = .10
  3127. mc.LeafyAltitude = .40
  3128. elif climate == GetInfoType("CLIMATE_COLD"):
  3129. mc.TundraThreshold = .35
  3130. mc.IceThreshold = .55
  3131. mc.MaxDesertAltitude = .25
  3132. mc.LeafyAltitude = .20
  3133. mc.EvergreenAltitude = .30
  3134. def GetRainfall(x,y):
  3135. rainfall = 0
  3136. i = GetIndex(x,y)
  3137. regionID = regMap.regionMap[i]
  3138. if regionID != -1:
  3139. region = regMap.getRegionByID(regionID)
  3140. rainfall = region.moisture
  3141. riverSize = GetRiverSize(x,y)
  3142. riverSizeMax = float(mc.RiverThreshold) * mc.RiverAddsMoistureMax
  3143. riverSize = min(riverSize,riverSizeMax)
  3144. rainfall += (riverSize/riverSizeMax) * mc.RiverAddsMoistureRange
  3145. return rainfall
  3146. def GetDistance(x,y,dx,dy):
  3147. distance = math.sqrt(abs((float(x - dx) * float(x - dx)) + (float(y - dy) * float(y - dy))))
  3148. return distance
  3149. ###############################################################################
  3150. #functions that civ is looking for
  3151. ###############################################################################
  3152. '''
  3153. # FF: Added by Jean Elcard 11/20/2008
  3154. def getNumCustomMapOptions():
  3155. return 3 + mst.iif( mst.bMars, 0, 1 )
  3156. def getNumHiddenCustomMapOptions():
  3157. """ Default is used for the last n custom-options in 'Play Now' mode. """
  3158. return 2 + mst.iif( mst.bMars, 0, 1 )
  3159. def getCustomMapOptionName(argsList):
  3160. [iOption] = argsList
  3161. option_names = {
  3162. 0: "Shape",
  3163. 1: "Peaks",
  3164. 2: "Starts",
  3165. 3: "Team Start"
  3166. }
  3167. translated_text = unicode(CyTranslator().getText(option_names[iOption], ()))
  3168. return translated_text
  3169. def getNumCustomMapOptionValues(argsList):
  3170. [iOption] = argsList
  3171. option_values = {
  3172. 0: 3,
  3173. 1: 11,
  3174. 2: 2,
  3175. 3: 3
  3176. }
  3177. return option_values[iOption]
  3178. def getCustomMapOptionDescAt(argsList):
  3179. [iOption, iSelection] = argsList
  3180. selection_names = {
  3181. 0: {
  3182. 0: "Flat World (default)",
  3183. 1: "Cylinder World (X Wrap)",
  3184. 2: "Toroidal World (X and Y Wrap)"
  3185. },
  3186. 1: {
  3187. 0: "No Softening (default)",
  3188. 1: "10% less Peaks",
  3189. 2: "20% less Peaks",
  3190. 3: "30% less Peaks",
  3191. 4: "40% less Peaks",
  3192. 5: "50% less Peaks",
  3193. 6: "60% less Peaks",
  3194. 7: "70% less Peaks",
  3195. 8: "80% less Peaks",
  3196. 9: "90% less Peaks",
  3197. 10: "No Peaks"
  3198. },
  3199. 2: {
  3200. 0: "Use Erebus Starting Plot Finder (default)",
  3201. 1: "Use Original Civilization IV Method"
  3202. },
  3203. 3: {
  3204. 0: "Team Neighbors",
  3205. 1: "Team Separated",
  3206. 2: "Randomly Placed"
  3207. }
  3208. }
  3209. translated_text = unicode(CyTranslator().getText(selection_names[iOption][iSelection], ()))
  3210. return translated_text
  3211. def getCustomMapOptionDefault(argsList):
  3212. [iOption] = argsList
  3213. option_defaults = {
  3214. 0: 0,
  3215. 1: 0,
  3216. 2: 0,
  3217. 3: 0
  3218. }
  3219. return option_defaults[iOption]
  3220. def isRandomCustomMapOption(argsList):
  3221. [iOption] = argsList
  3222. option_random = {
  3223. 0: True,
  3224. 1: True,
  3225. 2: False,
  3226. 3: False
  3227. }
  3228. return option_random[iOption]
  3229. # FF: End Add
  3230. '''
  3231. def generatePlotTypes():
  3232. NiTextOut("Generating Plot Types ...")
  3233. print "Adding Terrain"
  3234. gc = CyGlobalContext()
  3235. mmap = gc.getMap()
  3236. mapSize.MapWidth = mmap.getGridWidth()
  3237. mapSize.MapHeight = mmap.getGridHeight()
  3238. PRand.seed()
  3239. SetClimateOptions()
  3240. print "MapWidth = %(mw)d,MapHeight = %(mh)d" % {"mw":mapSize.MapWidth,"mh":mapSize.MapHeight}
  3241. plotTypes = [PlotTypes.PLOT_OCEAN] * (mapSize.MapWidth*mapSize.MapHeight)
  3242. NumberOfPlayers = gc.getGame().countCivPlayersEverAlive()
  3243. regMap.createRegions()
  3244. riverMap.createRiverMap()
  3245. plotMap.createPlotMap()
  3246. for i in range(mapSize.MapWidth*mapSize.MapHeight):
  3247. mapLoc = plotMap.plotMap[i]
  3248. if mapLoc == plotMap.PEAK:
  3249. plotTypes[i] = PlotTypes.PLOT_PEAK
  3250. elif mapLoc == plotMap.HILLS:
  3251. plotTypes[i] = PlotTypes.PLOT_HILLS
  3252. elif mapLoc == plotMap.LAND:
  3253. plotTypes[i] = PlotTypes.PLOT_LAND
  3254. else:
  3255. plotTypes[i] = PlotTypes.PLOT_OCEAN
  3256. print "Finished generating plot types."
  3257. return plotTypes
  3258. def generateTerrainTypes():
  3259. NiTextOut("Generating Terrain ...")
  3260. print "--- generateTerrainTypes()"
  3261. gc = CyGlobalContext()
  3262. map = CyMap()
  3263. terrainMap.createTerrainMap()
  3264. ########## Temudjin START
  3265. # Planetfall: more highlands
  3266. mst.planetFallMap.buildPfallHighlands()
  3267. # Prettify the map - change coastal peaks to hills with 30% chance; default: 66%
  3268. mst.mapPrettifier.hillifyCoast( 30 )
  3269. # Prettify map: Connect small islands
  3270. # mst.mapPrettifier.bulkifyIslands()
  3271. if mst.bPfall:
  3272. # convert terrainMap into Planetfall terrainMap
  3273. print "Latitude Borders: %r" % ( mst.getLatitudeBorders() )
  3274. terrainTypes = [0]*(mapSize.MapWidth*mapSize.MapHeight)
  3275. terrainList = [ 7, 6, 0, 1, 4, 9, 3, 2 ] # Ocean, Coast, Desert, Plains, Grass, Marsh, Tundra, Snow
  3276. for i in range( CyMap().numPlots() ):
  3277. terrainTypes[i] = mst.planetFallMap.mapPfallTerrain( terrainMap.terrainMap[i], terrainList, CyMap().plotByIndex(i) )
  3278. print "Latitude Borders: %r" % ( mst.getLatitudeBorders() )
  3279. elif mst.bMars:
  3280. # There are two possible scenarios for 'Mars Now!':
  3281. # either water is converted to desert or not
  3282. iDesert = mst.iif( mst.bSandsOfMars, 16, 32 )
  3283. terrainGen = mst.MST_TerrainGenerator_Mars( iDesert )
  3284. terrainTypes = terrainGen.generateTerrain()
  3285. else:
  3286. ########## Temudjin END
  3287. terrainTypes = [0]*(mapSize.MapWidth*mapSize.MapHeight)
  3288. for i in range(mapSize.MapWidth*mapSize.MapHeight):
  3289. if terrainMap.terrainMap[i] == terrainMap.OCEAN:
  3290. terrainTypes[i] = mst.etOcean
  3291. elif terrainMap.terrainMap[i] == terrainMap.COAST:
  3292. terrainTypes[i] = mst.etCoast
  3293. elif terrainMap.terrainMap[i] == terrainMap.DESERT:
  3294. terrainTypes[i] = mst.etDesert
  3295. elif terrainMap.terrainMap[i] == terrainMap.PLAINS:
  3296. terrainTypes[i] = mst.etPlains
  3297. elif terrainMap.terrainMap[i] == terrainMap.GRASS:
  3298. terrainTypes[i] = mst.etGrass
  3299. elif terrainMap.terrainMap[i] == terrainMap.TUNDRA:
  3300. terrainTypes[i] = mst.etTundra
  3301. elif terrainMap.terrainMap[i] == terrainMap.ICE:
  3302. terrainTypes[i] = mst.etSnow
  3303. elif terrainMap.terrainMap[i] == terrainMap.MARSH:
  3304. terrainTypes[i] = mst.etMarsh
  3305. print "Finished generating terrain types."
  3306. print str(mst.etOcean)
  3307. print str(mst.etCoast)
  3308. print str(mst.etDesert)
  3309. print str(mst.etPlains)
  3310. print str(mst.etGrass)
  3311. print str(mst.etTundra)
  3312. print str(mst.etSnow)
  3313. print str(mst.etMarsh)
  3314. return terrainTypes
  3315. '''
  3316. def addRivers2():
  3317. NiTextOut("Adding Rivers....")
  3318. print "Adding Rivers"
  3319. gc = CyGlobalContext()
  3320. pmap = gc.getMap()
  3321. for y in range(mapSize.MapHeight):
  3322. for x in range(mapSize.MapWidth):
  3323. placeRiversInPlot(x,y)
  3324. def placeRiversInPlot(x,y):
  3325. gc = CyGlobalContext()
  3326. pmap = gc.getMap()
  3327. plot = pmap.plot(x,y)
  3328. #NE
  3329. xx,yy = riverMap.rxFromPlot(x,y,riverMap.NE)
  3330. ii = riverMap.getRiverIndex(xx,yy)
  3331. if riverMap.riverMap[ii] > mc.RiverThreshold and riverMap.flowMap[ii] == riverMap.S:
  3332. plot.setWOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH)
  3333. #SW
  3334. xx,yy = riverMap.rxFromPlot(x,y,riverMap.SW)
  3335. ii = riverMap.getRiverIndex(xx,yy)
  3336. if riverMap.riverMap[ii] > mc.RiverThreshold and riverMap.flowMap[ii] == riverMap.E:
  3337. plot.setNOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_EAST)
  3338. #SE
  3339. xx,yy = riverMap.rxFromPlot(x,y,riverMap.SE)
  3340. ii = riverMap.getRiverIndex(xx,yy)
  3341. if riverMap.riverMap[ii] > mc.RiverThreshold and riverMap.flowMap[ii] == riverMap.N:
  3342. plot.setWOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_NORTH)
  3343. elif riverMap.riverMap[ii] > mc.RiverThreshold and riverMap.flowMap[ii] == riverMap.W:
  3344. plot.setNOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_WEST)
  3345. '''
  3346. def addFeatures2():
  3347. NiTextOut("Generating Features ...")
  3348. print "Adding Features"
  3349. gc = CyGlobalContext()
  3350. mmap = gc.getMap()
  3351. FORESTLEAFY = 0
  3352. FORESTEVERGREEN = 1
  3353. FORESTSNOWY = 2
  3354. #Now plant forest or jungle and place floodplains and oasis
  3355. for y in range(mapSize.MapHeight):
  3356. for x in range(mapSize.MapWidth):
  3357. plot = mmap.plot(x,y)
  3358. plotTerrain = plot.getTerrainType()
  3359. #forest and jungle
  3360. if not plot.isWater() and plotTerrain != mst.etDesert and not plot.isPeak():
  3361. #Chance for trees based on rainfall
  3362. rainfall = GetRainfall(x,y)
  3363. if rainfall >= PRand.random():#Trees are present
  3364. altitude = GetPlotAltitude(x,y)
  3365. if plotTerrain == mst.etTundra or plotTerrain == mst.etSnow: #Safeguard for possibly modified tiles
  3366. plot.setFeatureType(mst.efForest, FORESTSNOWY)
  3367. elif altitude < mc.LeafyAltitude:
  3368. if rainfall >= mc.JungleThreshold:
  3369. if plot.isFlatlands() and PRand.random() < mc.ChanceForMarsh:
  3370. plot.setTerrainType(mst.etMarsh,True,True)
  3371. if PRand.random() >= mc.ChanceForOnlyMarsh:
  3372. plot.setFeatureType(mst.efJungle,0)
  3373. else:
  3374. plot.setFeatureType(mst.efJungle,0)
  3375. else:
  3376. if altitude < mc.EvergreenAltitude:
  3377. plot.setFeatureType(mst.efForest, FORESTLEAFY)
  3378. elif altitude < mc.TundraThreshold:
  3379. plot.setFeatureType(mst.efForest, FORESTEVERGREEN)
  3380. else:
  3381. plot.setFeatureType(mst.efForest, FORESTSNOWY)
  3382. elif altitude < mc.EvergreenAltitude:
  3383. plot.setFeatureType(mst.efForest, FORESTLEAFY)
  3384. elif altitude < mc.TundraThreshold:
  3385. plot.setFeatureType(mst.efForest, FORESTEVERGREEN)
  3386. else:
  3387. plot.setFeatureType(mst.efForest, FORESTSNOWY)
  3388. #scrub
  3389. if mst.bScrub and plotTerrain == mst.etDesert and not plot.isPeak() and not plot.isHills():
  3390. rainfall = GetRainfall(x,y)
  3391. randValue = PRand.random()
  3392. if rainfall * 3.0 >= randValue:
  3393. plot.setFeatureType(mst.efScrub, 0)
  3394. ################Sat
  3395. ### added ###23
  3396. ### by Opera ###05
  3397. ################09
  3398. ## Kelp ; chance: 25% of spawning on Coasts
  3399. if mst.bKelp != -1 and plot.isCoastalLand():
  3400. randValue = PRand.randint(1,100)
  3401. if randValue > 75:
  3402. if plot.isWater():
  3403. plot.setFeatureType(mst.efkelp, 0)
  3404. ## Crystal Plains ; Chance function of surrounding tiles
  3405. if mst.bCrystalPlains and plotTerrain == mst.etSnow and not plot.isPeak() and not plot.isHills():
  3406. # Base chance;
  3407. # equal to 25% if iTemp=1
  3408. # equal to 12.5% if iTemp=2
  3409. # equal to 8.33% if iTemp=3
  3410. iChance = 25
  3411. iTemp = 1
  3412. if plot.isRiver() == True:
  3413. iChance += 5 # Rivers increase base chance
  3414. for xx in range(x-1,x+2):
  3415. for yy in range(y-1,y+2): # Checks surrounding plots
  3416. surPlot = mmap.plot(xx,yy)
  3417. if surPlot.getTerrainType() == mst.etSnow or surPlot.getTerrainType() == mst.etTundra:
  3418. if surPlot.isRiver(): # Surrounding plot river also increase chance
  3419. iChance += 2
  3420. if surPlot.getFeatureType() == mst.efCrystalPlains:
  3421. iChance += 3
  3422. else: # If neither Crystal Plains nor river but Snow or Tundra
  3423. iChance += 1
  3424. elif surPlot.getTerrainType() == mst.etDesert:
  3425. # Desert increases iTemp and decreases chance
  3426. iTemp = 3
  3427. iChance -= 4
  3428. elif surPlot.getTerrainType() != mst.etSnow:
  3429. # Terrains that aren't Snow, Tundra or Desert
  3430. iTemp = 2
  3431. iChance -= 2
  3432. # Here iTemp is used to reduce the chance of CP if the temperature is to high
  3433. rand = PRand.randint(1,100) * iTemp
  3434. if rand <= iChance:
  3435. plot.setFeatureType(mst.efCrystalPlains,0)
  3436. ## Haunted Lands ; mostly random (2%) but 33% if city ruins nearby
  3437. if mst.bHauntedLands and not plot.isPeak() and not plot.isWater():
  3438. if plot.getImprovementType() == mst.eiCityRuins:
  3439. for xx in range(x-1,x+2):
  3440. for yy in range(y-1,y+2):
  3441. surPlot = mmap.plot(xx,yy)
  3442. if surPlot.getFeatureType() != mst.efHauntedLands and not surPlot.isPeak() and not surPlot.isWater():
  3443. if PRand.randint(1,100) <= 33:
  3444. surPlot.setFeatureType(mst.efHauntedLands,0)
  3445. plot.setFeatureType(mst.efHauntedLands,0)
  3446. else:
  3447. if PRand.randint(1,100) <= 2:
  3448. plot.setFeatureType(mst.efHauntedLands,0)
  3449. ################
  3450. ### end of ###
  3451. ### addition ###
  3452. ################
  3453. #floodplains and Oasis
  3454. if plotTerrain == mst.etDesert and not plot.isHills() and not plot.isPeak() and not plot.isWater():
  3455. if plot.isRiver() == True:
  3456. plot.setFeatureType(mst.efFloodPlains, 0)
  3457. else:
  3458. #is this square surrounded by desert?
  3459. foundNonDesert = False
  3460. #print "trying to place oasis"
  3461. for yy in range(y - 1,y + 2):
  3462. for xx in range(x - 1,x + 2):
  3463. surPlot = mmap.plot(xx,yy)
  3464. if surPlot.getTerrainType() != mst.etDesert and not surPlot.isPeak():
  3465. #print "non desert neighbor"
  3466. foundNonDesert = True
  3467. elif surPlot == 0:
  3468. #print "neighbor off map"
  3469. foundNonDesert = True
  3470. elif surPlot.isWater() == True:
  3471. #print "water neighbor"
  3472. foundNonDesert = True
  3473. elif surPlot.getFeatureType() == mst.efOasis:
  3474. #print "oasis neighbor"
  3475. foundNonDesert = True
  3476. if foundNonDesert == False:
  3477. if PRand.random() < mc.OasisChance:
  3478. #print "placing oasis"
  3479. plot.setFeatureType(mst.efOasis, 0)
  3480. ########## Temudjin Start
  3481. mst.featurePlacer.placeReefs()
  3482. ########## Temudjin End
  3483. return
  3484. ##mapSize.MapWidth = 68
  3485. ##mapSize.MapHeight = 68
  3486. ##regMap.createRegions()
  3487. ####regMap.PrintRegionMap(False)
  3488. ####regMap.PrintRegionList()
  3489. ####regMap.PrintRegionMap(True)
  3490. ##riverMap.createRiverMap()
  3491. ##riverMap.PrintFlowMap()
  3492. ##plotMap.createPlotMap()
  3493. ##plotMap.PrintPlotMap()
  3494. ##regMap.PrintRegionRxMap(False)
  3495. ##regMap.PrintRegionMap(True)