View Full Version : MapScriptTools (.. and Associated Maps)


Temudjin
Jul 15, 2010, 12:35 PM
MapScriptTools.py v1.02
------------------------------
AUTHOR:
Temudjin (2009-11)
PURPOSE:
Provide tools to facilitate map-making and adapting/enhancing existing maps.
Make maps compatible for 'Normal', 'Fall from Heaven 2', 'Planetfall' and 'Mars Now!' mods.


MapScriptTools.py provides functions and classes to:
- easily adapt maps for Planetfall or Mars Now!
- produce maps with special features for Fall from Heaven 2
- add Marsh terrain
- add Deep Ocean terrain
- make the map looking prettier/more realistic
- add special regions to the map
- replace and expand BonusBalancer (from Warlords)
- manipulate river creation: (starting from lakes, on islands)
- handle starting-positions for teams
- print various sorts of maps to the log file for testing
- print stats about mod and map
- find the path for Civ4, Mod or Log files
Also included are several maps using these new features.


NOTES:

- Not really intended for 'Final Frontier' based maps.

- Compatible with BtS 3.19.
I've run a short test with Warlords 2.13 and that worked fine too. The above statement seems to imply compatibility to BtS 3.13/3.17, but this isn't tested.
Actually the question of compatibility arises mostly with respect of recognizing and showing the right mod-versions in the log. Unless recognition of 'Planetfall', 'Mars Now!' and 'Fall from Heaven 2' fails, there shouldn't be any problems beyond logging false identifications.

- Multiplayer compatibility is unknown.
Seems probable though as all randomizations are centralized within the choose..() functions. Please tell me.

- MAC compatibility is unknown as the MAC uses Python 2.3. Now it seems likely though.
Sets are not built-in in Python 2.3. I believe I used them only in adjustShelfTrenches() & rimRivers() though.
! I think this is fixed. - Thanks EmperorFool
Also new in Python 2.4 was the use of the keyword parameter 'key' within the sort() method of lists. I used the key parameter name in makeMapLegend() & showContinents() only.
! I think this is fixed. - Thanks Xyth & EmperorFool
I've tried to fix all those MAC issues, both here and with the associated maps. Maybe now it's compatible? Please tell me.



To show how MapScriptTools are working I've included several adjusted Mapscripts:

Earth3_163_mst.py
by jkp1187 --> http://forums.civfanatics.com/showthread.php?t=253927
Erebus_107c_mst.py
by Cephalo --> http://forums.civfanatics.com/showthread.php?t=261688
Inland_Sea_131_mst.py
by Sirian (Civ4 original)
Medium_and_Small_111_mst.py
by Sirian (Civ4 original)
PerfectMongoose_3101_mst.py
by LunarMongoose --> http://forums.civfanatics.com/showthread.php?t=402816
PerfectWorld_206f1_mst.py
by Cephalo --> http://forums.civfanatics.com/showthread.php?t=310891
Planetfall_101_mst.py (**NEW**)
by Maniac --> http://forums.civfanatics.com/showthread.php?t=252829
Sea_Highlands_121_mst.py
by Sirian (Civ4 original)
SmartMap_922_mst.py (changed)
by surt --> http://forums.civfanatics.com/showthread.php?t=154989
Tectonics_316a_mst.py
by Laurent Di Cesare --> http://forums.civfanatics.com/showthread.php?t=149278
Ringworld3_102_mst.py (changed)
by Temudjin --> http://forums.civfanatics.com/showthread.php?t=371831
FracturedWorld_102_mst.py (changed)
by Temudjin --> http://forums.civfanatics.com/showthread.php?t=371842

All maps can be used with 'Fall from Heaven', 'Planetfall' or 'Mars Now!'.
All maps can (and will) produce Marsh terrain, if the mod supports it.
All maps can (and will) produce Deep Ocean terrain, if the mod supports it.
All maps allow for at least two more map sizes beyond 'Huge', if the mod supports them.
All maps support Coastal Waters options. (Allow expanded coast like Civ5)
All maps may add Map Regions ( BigDent, BigBog (not Mars), ElementalQuarter (FFH only), LostIsle ).
All maps may add Map Features ( Kelp, HauntedLands, CrystalPlains ), if supported by mod (FFH only).
All maps may add some rivers on small islands and from lakes.
All maps support Mars Theme options, if 'Mars Now!' is the active mod.
All maps support Team Start options.
All maps support any number of players, depending on the mod.
All maps produce printed maps in "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log"
All maps produce printed statistics in "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log"
If 'Planetfall' is the active mod, usually the planetfall-default starting plot finder will be used.
If 'Mars Now!' is the active mod, the 'Team Start' option will be suppressed.
If 'Mars Now!' is the active mod, oceans and lakes are converted to desert (Sands of Mars), except if Terraformed Mars is choosen in the Mars Theme options.
Most maps use balanced resources, add missing boni and try to move some minerals to nearby hills.
Most maps give names to their Special Regions.



************************************************
** Thanks:
** ---------
** I've looked into a lot of map-scripts and mod-code and learned much from the authors. I also
** stole ideas and sometimes even parts of code, which I found useful. I'm sorry to say that
** I don't remember all of my sources - my apologies and thank you all for your efforts.
** Specifically I'd like to thank:
**
** Ruff_Hi
** - Your 'Ring World' induced me into a deeper investigation of maps.
**
** The CivFanatics Community
** - For making all those wonderful maps and mods and
** for providing the opportunity to have a look at how it's done.
**
** The Civ4 Design Team
** - By opening your game-engine, you really opend the world(s).
**
************************************************


Installation:
Put the file MapScriptTools.py into the ...\Beyond the Sword\Assets\Python folder. (NOT CustomAssets!)

If you don't mind to see it as an option in the map selection of 'Custom Game', you can put it
into the ...\Beyond the Sword\PublicMaps folder, but that's the second best solution, as it won't work
if the mod disallows public maps in its ini-file (it may have other quirks - this isn't well tested).

'Planetfall' uses the PrivateMaps folder, here you whould either have to put it into the Python folder, or change the ini-file to allow 'Planetfall' to use the PublicMaps folder.

All reports go to the Python log normally at "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log".
You may have to enable logging by making sure the following option is set to 1 in "...\My Documents\My Games\Beyond the Sword\civilization.ini":
; Enable the logging system
LoggingEnabled = 1


Changelog:
1.02___29.Jul.11
- Fixed, path identification for MAC in getCivPaths()
- Fixed ??, MAC compatibility with key parameter in sort() method
- Fixed, Bonus-list now gives the correct mana-type for FFH type mods
- Changed, new optional parameter for printList() & sprintList()
- Changed, new optional parameter for featurePlacer.placeReefs() ! changes parameter order
- Changed, now two ways to recognize mana types automatically,
- as defined by the prerequisites for the Towers of Alteration/Divination/Necromancy/Elements; all other mana types are considered mana for meta-magics
- as defined by the mana type tech, that is the prerequisite of building the appropiate node on the mana boni
- Changed, in buildTerrainMap(), buildFeatureMap(),buildBonusMap() the showPlots parameter now defaults to False
- Improved, recognize 'Master of Mana', 'History Rewritten' mods
- Improved, put addGoodies() into the template
- Improved, whenever a reef is build in the ocean, there is now a chance that it expands into a somewhat longish chain of reefs
- Added, world shape to map description log
- Added, Planetfall_101_mst script

1.01___15.Mar.11
- Fixed ??, MAC compatibility with sets and in CivFolders.getCivPaths() - can't test this myself
- Fixed, incompatibility with 'History in the Making', 'Quod Capita', and possibly some other mods using newer BUG versions
- Fixed, proper initialization of 'Lost Isle' region upon regeneration of map
- Fixed, potential problem with region signs falling off the unwrapped map
- Fixed, now correct coast terrain with special regions
- Fixed, now Volcanos stand on Land/Hills plots - looks better than floating above peaks
- Fixed [Planetfall], 'Lost Isle' now produce proper marine boni
- Fixed [Mars Now!], 'Lost Isle' region now also on Mars
- Fixed [Mars Now!], no more rivers from 'BigBog' or 'BigDent'
- Fixed [Mars Now!], printed terrain/feature/bonus maps now show proper resource names
- Fixed [Mars Now!], no volcanos on marsian deserts anymore, if MST_FeatureGenerator is used
- Changed, new 'class MST_Terraingenerator_Mars' for use with 'Mars Now!', was split from 'class MST_Terraingenerator' which should be used otherwise
- Changed, minor changes producing special regions: 'BigDent' and 'BigBog'
- Changed [Planetfall], normal Trenches and Shelves on biggest ocean and a few more elsewhere
- Changed [Planetfall], BonusBalancer ignores options for balancing and finding boni
- Changed [Planetfall], Tundra conversion in planetFallMap.mapPfallTerrain() now: Tundra -> 33% FlatPolar, 16% RockyPolar, 33% FlatMoist, 16% RockyMoist
- Changed [Planetfall], Highland generation in planetFallMap.buildPfallHighlands() now gives more hills/peaks, which are more clustered together - like Planetfall
- Changed [Mars Now!], converting ocean to desert: some few hills are created and at higher latitudes tundra or even some ice may be created
- Changed, some default parameters within various methods - still balancing things
- Improved, streamlined num...Neighbors() mapping functions
- check number of plot-neighbors for lists of plots, terrain, features, boni or improvements
- killed obsolete bWrap parameter
- Improved, less chance for 'BigBog' and 'BigDent' to start on small island and better chance to start inside bigger continent
- Improved, print version to log
- Added, new class variable 'riverMaker.maxRiverLength' to cap length of river
- Added, feature generator for Mars Now! (included in class MST_FeatureGenerator)
- Added to 'featurePlacer', methods to place Reefs and Scrub on the map, if allowed by mod
- Added to 'mapPrettifier', method lumpifyFeature()
- Added, parameter to getModInfo(), to allow suppression of region-names
- Added, parameter to mapRegions.buildBigBog() and mapRegions.buildBigDent() to control chances for each special region to exist; slightly lowered default chance (now 66%).
- Added, parameter to printDict() and printList(), to format floating-point output
- Added, parameter to mapStats.statPlotCount() to enable use before plots are generated
- Added [Planetfall], parameter and result to planetFallMap.buildPfallHighlands() to enable use before plots are generated
- Added [Planetfall], name signs for already known Planetfall regions: 'Mount Planet', 'Garland Crater', 'Manifold Nexus', 'The Great Dunes', 'Pholus Ridge', 'The Ruins', 'Borehole Cluster'
- Added [Mars Now!], new global variable: bSandsOfMars, denoting a map on Mars, where all surface water is converted to desert.
- Added Info, included 'How To Guide' and updated the 'MapScriptTools Interface Template' ---> see the end of MapScriptTools.py file!

1.00___15.Jul.10
Initial release



Known Errors:
-

Temudjin
Jul 15, 2010, 12:36 PM
MapScriptTools Manual and API Ver.: 1.02

Introduction:

If you're a modder working (or playing!) with map-scripts, this is for you!


The tools in MapScriptTools.py allow you to:

1 ) Transform any map-script into one suitable for 'Planetfall' or 'Mars Now!'.
1a) Use a template that for most mapscripts has to be only moderately adjusted.
2 ) Introduce new terrains into any map-script.
2a) Put Marsh Terrain on the map. If the mod supports it.
2b) Put Deep Ocean Terrain on the map. If the mod supports it.
3 ) Create odd regions on the map:
3a) 'The Big Bog', a flat, marshy, somewhat round region, probably with a lake and some rivers within it.
3b) 'The Big Dent', a mountainous, somewhat oval region, probably with a volcano and several rivers flowing from it.
3c) 'Elemental Quarter', the place where elemental mana nodes meet. Earth, Water, Air and Fire nodes influence the quarter of featureless terrain behind them. (For FFH only)
3d) The lost 'Isle Of Atlantis' / 'Numenor Island', a small, isolated island with city-ruins, roads, and perhaps some intact improvements. If allowed by the mod, some other goodies may also appear.
4 ) Put mod-dependent features on the map:
4a) Kelp on coastal plots
4b) Haunted Lands in deep forest, deep desert, within and around marshes, near ruins and mountain passes.
4c) Crystal Plains on snowy flatland plots.
5 ) Greatly expand upon the BonusBalancer class from Warlords in CyMapGeneratorUtil.py. Allows for mod-specific bonus-lists (currenty only Civ and FFH, but you can supply your own).
5a) Gives each player a fair chance to find the neccessary resources within a reasonable radius. If that radius overlaps with your neighbors, you may have to fight over that resource anyway.
5b) Places missing boni (those boni which should have been but for some reason weren't placed by addBonus()).
5c) Moves some minerals [Copper,Iron,Mithril,Uranium,Silver] placed on flatlands to nearby hills. Create those hills if necessary and wanted.
6 ) Place rivers on the map.
6a) Enable building rivers starting at the sea and moving upriver.
6b) Put a river (or two) on smaller islands.
6c) Automatically start river(s) from lake(s).
6d) Produce river-lists. Print their coordinates. (As yet only of those rivers created by buildRiver())
7 ) Allow teams to have nearby, separated or random starting-plots.
8 ) Print maps to the Python log at "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log":
8a) Area-Maps
8b) Plot-Maps
8c) Terrain-Maps (Normal and Planetfall) - allow user supplied list of terrain.
8d) Feature-Maps (Normal and Planetfall) - allow user supplied list of features.
8e) Bonus-Maps (Normal and Planetfall) - allow user supplied list of boni.
8f) River-Maps (plots,river-flows and starting-plots)
8g) Difference-Maps of an earlier map and the actual map can be produced to document the different stages of map building.
9 ) Print stats of map and mod to the Python log at "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log".
10) Prettify maps:
10a) Connect small lakes.
10b) Connect small islands.
10c) Connect small terrain patches.
10d) Remove ice from edge of map.
10e) Adjust plot / terrain frequency to given percentage.
10f) Reduce peaks and volcanos for graphical beautification.
10g) Expand coastal waters
11 ) Find the path for Civ4, Mod or Log files
12 ) Groups of single funtion helpers:
12a) Deal with areas.
12b) Deal with (cardinal) directions.
12c) Choose randomly - don't deal with dices anymore.
12d) Convert between plot, index and coordinates.
12e) Check numbers of neighbor plot-types, terrains, features.
13 ) A whole lot of other goodies.


Compatibility:

The 'MapScriptTools' are compatible with BtS 3.19.
I've run a short test with Warlords 2.13 and that worked fine too.
The above statements seem to imply compatibility to BtS 3.13 / 3.17, but this isn't tested.


Import MapScriptTools:

Before using the MapScriptTools (MST), they have to be imported by the script.
Use 'import MapScriptTools as mst' somewhere at the beginning of your file.


Output:

All reports go to the Python log normally at "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log".
You may have to enable logging by making sure the following option is set to 1 in "...\My Documents\My Games\Beyond the Sword\civilization.ini":

; Enable the logging system
LoggingEnabled = 1


Initialization:

To use most of the goodies within the MapScriptTools, they have to be initialized.
The getModInfo() function is used for this purpose. It should be the first
MST function executed. Putting 'mst.getModInfo()' first into beforeGeneration() seems like a good idea. Actually the function has optional parameters which you probably want to use.


Functions:


getModInfo(mapVersion=None, defLatitude=None, sMapInfo=None, bNoSigns=False)
..............................................
Initialize MapScriptTools and print basic map parameters to the log. Identify mod if possible.

mapVersion (string or None)
- Version of map-script
defLatitude (string or None)
- String to be evaluated by evalLatitude(). The string-function can only see x and y as variables and should return the latitude of a plot at coordinates x,y as a value between 0 .. 90.
sMapInfo (string or None)
- String to be printed into the log with infos about the selected map parameters.
bNoSigns (bool)
- Suppress names for special map-regions

Return: -

evalLatitude(plot, bDegrees=True)
..............................................
Evaluate defLatitude given in getModInfo(), to give the latitude for any plot. MapScriptTools doesn't know how latitudes are calculated in each different map-script. This is the mechanism to enable the internal functions to get the latitude for their climate calculations.

plot (plot)
- Plot on the map for which the latitude is sought.
bDegrees (bool)
- If True the result will be an integer between 0 .. 90, if False the result will be floating-point beween 0.0 .. 1.0, equator is zero.

Return: Latitude of plot in the form indicated by bDegrees.


Instantiated Classes:


class CivFolders:
instance: civFolders
.............................
Find out where the files are.
.............................
getModPaths() Example:

civFolders.appName = "Beyond the Sword"
civFolders.userDir = "....\My Documents\My Games"
civFolders.rootDir = "....\My Documents\My Games\Beyond the Sword"
civFolders.logDir = "....\My Documents\My Games\Beyond the Sword\Logs"
civFolders.appDir = "..\Civilization 4\Beyond the Sword"
civFolders.modName = "MyMod"
civFolders.modFolder = "Mods\MyMod"
civFolders.modDir = "..\Civilization 4\Beyond the Sword\Mods\MyMod"


class DeepOcean:
instance: deepOcean
..............................................
put 'Deep Ocean' terrain into the middle of the oceans.
..............................................
buildDeepOcean( dist=3, chDeep=80 )


class PlanetFallMap:
instance: planetFallMap
..............................................
All that's needed to change maps into 'Planetfall' maps.
..............................................
buildPfallOcean()
pFallTerrain = mapPfallTerrain( eTerrain, terList, plot, terrainGen=None )
buildPfallHighlands( iBaseChance=None )


class MapPrettifier:
instance: mapPrettifier
......................................
Something to make maps look beautiful.
......................................
connectifyLakes( chConnect=75 )
deIcifyEdges( iLat=66 )
hillifyCoast( chHills=50 )
expandifyCoast( ch=15, passes=4 )
beautifyVolcanos( chHills=66 )
lumpifyTerrain( targetTerrain, sourceTer1, sourceTer2=None )
lumpifyFeature( targetFeature, sourceFeat1, sourceFeat2=None, passes=1 )
bulkifyIslands( chConnect=66, maxIsle=4 )
percentifyTerrain( targetTerTuple, *sourceTerTuples )
percentifyPlots( targetPlotType, fTargetPlotPercent, data=None, terGenerator=None )


class MarshMaker:
instance: marshMaker
..............................................
If the mod allows marsh-terrain, it can be made here.
..............................................
bModHasMarsh = initialize( iGrassChance=5, iTundraChance=10, tMarshHotRange=(0,18), tMarshColdRange=(45,63) )
convertTerrain( tAreaRange=None, areaID=None )
iArid = getAridity()
normalizeMarshes()


class MapRegions:
instance: mapRegions
..............................................
Some regions on the map can be distinctive (and may have a name).
..............................................
initialize( regDist=15, noSigns=False )
buildLostIsle( chance=33, minDist=7, bAliens=False )
centerPlot = theLostIsle( pCenterPlot, pList, bAliens )
buildBigBogs( iBogs=None, chDent=66 )
namePlot = theBigBog( pCenterPlot, bBigBog=True, bBogLake=True )
buildBigDents( iDents=None, chDent=66 )
namePlot = theBigDent( pCenterPlot, bSideways=None, chAccess=66 )
buildElementalQuarter( chEQ=66 )
namePlot = theElementalQuarter( pCenterPlot, temp )
addRegionExtras()
bValid = regionCheck( plot, regionDistance=None )
--- vars ---
mapRegions.noSigns
- a toggle to determine if landmark signs should show
mapRegions.regionList
- a list of coordinates for the different regions, one [x,y] per region.


class FeaturePlacer:
instance: featurePlacer
..............................................
Put some common mod-dependent features on the map.
..............................................
placeFeatures()
placeReefs( chReef=3, chExpand=20, maxLatitude=None )
placeScrub( chScrub=10 )
placeKelp( chKelp=20, bAll=False, bLakes=False )
placeHauntedLands( chHaunted=6 )
placeCrystalPlains( chCrystal=20 )


class BonusBalancer:
instance: bonusBalancer
..............................................
Deal with resources. Balance them and make sure all are on the map and where they belong.
..............................................
initialize( bBalanceOnOff=True, bMissingOnOff=True, bMineralsOnOff=True, bWideRange=False )
normalizeAddExtras( *lResources )
bSkip = isSkipBonus( iBonusType )
bValid = isBonusValid( eBonus, pPlot, bIgnoreUniqueRange, bIgnoreOneArea, bIgnoreAdjacent )
addMissingBoni()
moveMinerals( lMineralsToMove=None )


class RiverMaker:
instance: riverMaker
..............................................
Build rivers coming either down from the mountains or up from the sea. Put rivers on islands.
..............................................
buildRiver( pStartPlot, bDownFlow=True, ecNext=None, ecOri=None, iThisRiverID=None, riverList=None )
islandRivers( minIsle=6, maxIsle=50, areaID=None )
buildRiversFromLake( lakeAreaID=None, chRiver=66, nRivers=1, minLake=1 )
sList = outRiverList( riverList )
bEdge = isEdgeDirection( self, plot, ecDir )
bRiver = hasRiverAtPlot( plot )
bCorner = hasRiverAtSECorner( plot )
bCorner = hasCoastAtSECorner( plot )
bCorner = hasPlotTypeAtSECorner( plot, plotType )
eCard = getBestFlowDir( plot, bDownFlow=True, bShort=False, eForbiddenList=[] )


class TeamStart:
instance: teamStart
..............................................
Put starting-plots of team members together or separated.
..............................................
placeTeamsTogether( bTogether=False, bSeparated=False )
bTeams = getTeams()


class MapPrint:
instance: mapPrint
.................................
Have a look at what you've built.
.................................
initialize()
definePrintMap( lines, charsPerPlot, linesPerPlot, mapTitle="", region=None, offset=None, mapLegend="" )
printMap( diffDict=None )
bSuccess = buildDiffMap( newDict, oldDict )
buildAreaMap( bDiffDict=False, sTitle=None, region=None, areaID=None, areaDict=None )
buildPlotMap( bDiffDict=False, sTitle=None, region=None, data=None )
buildTerrainMap( bDiffDict=False, sTitle=None, region=None, terrainDict=None, showPlots=True )
buildFeatureMap( bDiffDict=False, sTitle=None, region=None, featureDict=None, showPlots=True )
buildBonusMap( bDiffDict=False, sTitle=None, region=None, bonusDict=None, showPlots=True )
buildRiverMap( bDiffDict=False, sTitle=None, region=None )


class MapStats:
instance: mapStats
...............................
Don't you just love statistics?
...............................
mapStatistics( bFullVersion=True )
tPlotStats = statPlotCount( txt=None )
showContinents( txt=None, minPlots=3, bWater=False )
sTechs = getTechList( prefix = "", bTechLevels=True )
listPlayers = getCivPlayerList()
sprint = sprintActiveCivs( showTeams=False, showTraits=False, showHumans=False )


class RandomList:
instance: randomList
.......................................
Just little helpers to randomize lists.
.......................................
newlist = xshuffle( oriList )
shuffle( oriList )
countList = randomList.randomCountList( count )


Uninstantiated Classes:

class MST_TerrainGenerator(CvMapGeneratorUtil.TerrainGen erator):
.................................................. .............
Make sure the right latitudes are used when generating terrain.
.................................................. .............
lat = getLatitudeAtPlot( iX, iY )


class MST_TerrainGenerator_Mars(MST_TerrainGenerator):
.................................................. .............
Generate terrain for 'Mars Now!'.
.................................................. ....
terrainVal = generateTerrainAtPlot( iX, iY ):


class MST_FeatureGenerator(CvMapGeneratorUtil.FeatureGen erator):
.................................................. ..............
Make sure the right latitudes are used when generating features.
.................................................. ..............
lat = getLatitudeAtPlot( iX, iY )


Useful Functions:

There are quite a few little 'helper' files near the top of this file,
which may well be usefull to you. If you used 'import MapScriptTools as mst',
you can use them all by putting 'mst.' before the call.
Have a look and feel free to do with them what you want.


Useful Constants:


mst.bPfall True,False
indicates if this mod is 'Planetfall' or a modmod
( checks for BONUS_FUNGICIDE )

mst.bPfall_Scattered True,False - ONLY for Planetfall
indicates if mod-option 'Scarrered Landing Pods' is active

mst.bMars True,False
indicates if this mod is 'Mars Now!' or a modmod
( checks for 'Mars, Now!' in pedia )

mst.bSandsOfMars True,False - default is False, except on Mars where the default if True.
indicates if 'Sands of Mars' theme is used, where open water is converted to desert.

mst.bFFH True,False
indicates if this mod is 'Fall From Heaven 2' or a modmod
( checks for BONUS_MANA )

mst.bFFront True,False
indicates if this mod is 'Final Frontier' or a modmod
( checks for FEATURE_SOLAR_SYSTEM )

mst.bPatch True,False
indicates if the 'CvGameCoreDLL.dll' of this mod incorporates the 'Unofficial Patch'
( checks results of plot.getLatitude() )

mst.bRev True,False
indicates if this mod is or incorporates the RevolutionDCM-Mod

mst.bBUG True,False
indicates if this mod is or incorporates the BUG-Mod

mst.bBBAI True,False
indicates if this mod is or incorporates the BBAI-Mod

mst.bAIAuto True,False
indicates if this mod incorporates 'AI AutoPlay'


Notes:

These tools are for the english version only.
Several tests depend on text found in various xml-files. To be more precise:
The english text! Of the checks mentioned that would be bBUG, bBBAI and bAIAuto
together with most other mod-recognition checks.
Any failure of the tests will probably just affect the stats though.

Python 2.4 doesn't really have much of a concept for private data. The
class methods below the ---private--- line are as readily accessible as
the others, but they are not part of the API and thus subject to change
without notice.
( Just like anything else really - I'm giving no guarantees, but I might think twice.)



Included Mapscripts:


To use the MapScriptTools with existing mapscripts, just put the included template-script
into them and modify as needed. To demonstarte how it is done I've included several altered
mapscripts. Some mapscripts required additional changes - sorry, but it's not quite automated (yet)
and you still need some understanding of what you are doing.


All maps can be used with 'Fall from Heaven', 'Planetfall' or 'Mars Now!'.
All maps can (and will) produce Marsh terrain, if the mod supports it.
All maps can (and will) produce Deep Ocean terrain, if the mod supports it.
All maps allow for at least two more map sizes beyond 'Huge', if the mod supports them
All maps may add Map Regions ( BigDent, BigBog (not Mars), ElementalQuarter (FFH only), LostIsle ).
All maps may add Map Features ( Reef, Scrub, Kelp, HauntedLands, CrystalPlains ), if supported by mod.
All maps add some rivers on small islands and from lakes
All maps support Coastal Waters options. (Allow expanded coast like Civ5)
All maps support Team Start options. (Choose to find your teammate either near or far)
All maps support Mars Theme options, if 'Mars Now!' is the active mod.
All maps support any number of players, depending on the mod.
All maps produce printed maps in "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log"
All maps produce printed statistics in "...\My Documents\My Games\Beyond the Sword\Logs\PythonDbg.log"
If 'Planetfall' is the active mod, usually the planetfall-default starting plot finder will be used.
If 'Mars Now!' is the active mod, the Team Start option will be suppressed.
If 'Mars Now!' is the active mod, oceans and lakes are converted to desert (Sands of Mars),
except if Terraformed Mars is choosen in the Mars Theme options.
Most maps use balanced resources, add missing boni and try to move some minerals to nearby hills.

Earth3_163_mst.py by jkp1187 --> http://forums.civfanatics.com/showthread.php?t=253927
- Adjusted starting-plot creation using: 'Temudjins Cool Starting Plots'
- Added New Zealand, Madagascar and changed Japan a bit.
- Added Himalayas (single BigDent at special place)

Erebus_107c_mst.py by Cephalo --> http://forums.civfanatics.com/showthread.php?t=261688
- Uses default river-system. Wasn't able to insert the new rivers of mapRegions.
- Opera already introduced placing of Kelp, HauntedLands, CrystalPlains for FFH

Inland_Sea_131_mst.py by Sirian (Civ4 original)
- Expanded the template system for starting-plots with generator for more than 18 players.

Medium_and_Small_11c_mst.py by Sirian (Civ4 original)
- The minimalistic approach

PerfectMongoose_3101_mst.py by LunarMongoose --> http://forums.civfanatics.com/showthread.php?t=402816
- I had to fiddle a bit in generateTerrainTypes() to transform the generated terrainList
- Uses default river-system. Wasn't able to insert the new rivers of mapRegions.

PerfectWorld_206f1_mst.py by Cephalo --> http://forums.civfanatics.com/showthread.php?t=310891
- I had to fiddle a bit in generateTerrainTypes() to transform the generated terrainList
- Uses default river-system. Wasn't able to insert the new rivers of mapRegions.

Planetfall_101_mst.py by Maniac --> http://forums.civfanatics.com/showthread.php?t=252829
- Converted the other way around: from Planetfall to Vanilla BtS, FFH and Mars

Sea_Highlands_121_mst.py by Sirian (Civ4 original)
- vbraun already added an option and changed some values; I changed some more to make ships useful.
- The MapScriptTools template is at the bottom of the file.
- Shows how to construct a moderatly complex evaluation string for evalLatitude().
- Eliminate Whale and Pearls boni.
- Flat map only.

SmartMap_922_mst.py by surt --> http://forums.civfanatics.com/showthread.php?t=154989
- Full BtS compatibility.
- Use both .Civ4WorldBuilderSave and .CivBeyondSwordWBSave files.
- Adjusted starting-plot creation using: 'Temudjins Cool Starting Plots'
- Some adjustment of Map Options - partly on the fly for 'Planetfall' and 'Mars Now!'.
- Lots of small changes in nearly all functions.

Tectonics_316a_mst.py by Laurent Di Cesare --> http://forums.civfanatics.com/showthread.php?t=149278
- Adjusted starting-plot creation using: 'Temudjins Cool Starting Plots'

Ringworld3_102_mst.py by Temudjin --> http://forums.civfanatics.com/showthread.php?t=371831
- My very own map-script, using lots of MapScriptTools features.

FracturedWorld_102_mst.py by Temudjin --> http://forums.civfanatics.com/showthread.php?t=371842
- My very own map-script, using lots of MapScriptTools features.


How To Guide:


How To Guide to transform a 'normal' map-script for MapScriptTools
- Make sure MapScriptTools.py is in the appropiate ...\Assets\Python folder: ..\Beyond the Sword\Assets\Python seems to be best as you need it only once.
- Put the following 'MapScriptTools Interface Template' into your map-script after the import statements.
- Comment-out / delete what you don't want.
- Make the necessary adjustments.
- For Planetfall and Mars use CyPythonMgr().allowDefaultImpl() for the default starting-plot finder.
- For Planetfall and Mars use mst.MST_FeatureGenerator() to generate features
- For Planetfall use mst.MST_TerrainGenerator() to generate terrain.
- For Mars use mst.MST_TerrainGenerator_Mars() to generate terrain.
- Have a care where (or if at all) you place the CyPythonMgr().allowDefaultImpl() statements. In assignStartingPlots(): CyPythonMgr().allowDefaultImpl() must be the last statement executed!
- Check for normalize...() functions in the map-script. Use those as a guideline for which normalizations to allow or not.
- Some map-scripts use the Warlords bonus balancer:
---Delete the lines:

from CvMapGeneratorUtil import BonusBalancer
balancer = BonusBalancer()

---The balancer is then used within normalizeAddExtras() and addBonusType(). If that's the only thing that's done in these functions, just delete them too.
---You may also adjust the mst.bonusBalancer call at the end of beforeGeneration().
- Some map-scripts use separate lists to manipulate terrain/rivers. See Erebus or PerfectWorld2 for a possible if imperfect way to handle that.
- You probably have to rename some of your functions too.
---If you find functions in the map-script with the same name as the newly inserted ones, check if you can just delete them too, or rename then and call them from within the new functions.
---Take some care as some actually return a value, which needs to be returned or assigned somewhere.
- Rename the new map-script to: yourmapname_mst.py

NOTES:
- There are always some adjustments to make.
- There is always an adjustment that's more complicated than anticipated.
- There may be a lot adjustments - not usually though.
- Placing bad code into minStartingDistanceModifier() may crash your computer.
- Feel free to delete any superfluous comments if they distract too much.


MapScriptTools Interface Template:

You find the template at the end of the MapScriptTools.py file.

The_J
Jul 15, 2010, 01:11 PM
:wow: that looks massive.

Now i only have to understand what it does :D. Okay, this is basically an "utility" to transform maps for different mods, right?
So i can plug one of the mentioned mapscripts in my mod (i feel honoured :)), put mst in my python folder, import mst into the mapscript, and then it will work?


Bah, i don't have my gaming pc here, so i can't test it :mad:.

Temudjin
Jul 15, 2010, 01:48 PM
Somehow it went bigger and bigger with time :rolleyes:.

Actually what you have to do is:
1) put MapScriptTools.py into the ...assets\python folder of your mod
2) put the mapscripts into the ...\PrivateMaps folder of your mod
that should be all.

You only need the line
import MapScriptTools as mst
if you want to write a new mapscript or mess with an existing one.
In that case you might want to look at the template I've put at the end of the file.

The_J
Jul 15, 2010, 02:04 PM
That's exactly what i understood, and that is...awesome :goodjob:.
I'll definitly try it out.


...wait, we can now use the erebus mapscript with vanilla BtS, right?

Maniac
Jul 15, 2010, 02:43 PM
My jaw is on the floor. Reads awesome at first sight. :eek: I'll need to check this out. :goodjob:

Temudjin
Jul 15, 2010, 02:55 PM
Yes,
Erebus_107b_mst.py should work with vanilla or just about any mod (except Final Frontier mods) :).

The_J
Jul 15, 2010, 06:22 PM
You are definitly great :goodjob:.

lordroy
Jul 16, 2010, 05:22 AM
I am using The Bat mod (that has smartmap)... can I replace the existing smartmap with this one?

Temudjin
Jul 16, 2010, 05:40 AM
@lordroy:

Very probably, as long as you've also put MapScriptTools.py into some appropriate ..\Assets\Python folder.

lordroy
Jul 16, 2010, 08:06 AM
Ya, it does seem to be working correctly. Thank you.

-=R=-

EmperorFool
Jul 16, 2010, 07:16 PM
You can fix the sets issue on the Mac with this generic code (works fine on Windows):


try:
# test if the 2.4 set class already exists
set
except:
# nope, so map it to the classes from the 2.3 sets module
import sets
set = sets.Set
frozenset = sets.ImmutableSet


Just put this at the top-level of the module, right after the imports. I believe you have code that detects the Civ4 folder, and I haven't checked if it handles Macs or not. You can swipe the code from BUG's BugPath.py (http://civ4bug.svn.sourceforge.net/viewvc/civ4bug/trunk/CustomAssets/Python/BUG/BugPath.py?view=log) for this, too.

Afforess
Jul 16, 2010, 11:54 PM
Wow, Nice. Adding this to my mod. Great Work!

Temudjin
Jul 17, 2010, 02:58 AM
@ EmperorFool
Thanks for the tip :hatsoff:. I may try this with the next patch/update :undecide:.
Actually I already swiped my path code mostly from BUG :smug: - except I left out the MAC related stuff and some other I didn't understand :rolleyes:. I guess I may have to revisit this :hmm:.

Jabarto
Jul 17, 2010, 07:40 PM
I have only the most basic understanding of how to use these tools, but I can tell that they have serious potential. :)

Maniac
Jul 18, 2010, 04:02 AM
I've looked into the code for MapScriptTools and generated a couple maps with the various mapscipts, and so far have noticed a couple differences with what I would consider maps suitable for my intended Planetfall gameplay. I'm wondering if you are aware of these differences, but they are intentional; or are aware of them but don't see a way to merge the Planetfall requirements with the specifics of the mapscripts; or are unaware of the differences; or are unaware of the intentions I have with the mapscripts; or something else.

***

First thing I noticed was in the code for generation terrain types:

It says:

elif eTerrain==itTundra: pfallTerrain = choose( 66, etRockyMoist, etFlatPolar )

In Planetfall's CvMapGeneratorUtil, Tundra gets changed to 33% Flat Polar, 33% Flat Moist, 16% Rocky Moist and 16% Rocky Polar. What is the reason behind this difference?

Also what does this code do?

if pfallTerrain==etRockyArid and pLatitude<fDesBot: pfallTerrain = choose( 66, etRockyMoist, etRockyArid )
elif pfallTerrain==etFlatArid and pLatitude<fDesBot: pfallTerrain = choose( 66, etFlatMoist, etFlatArid )
elif pfallTerrain==etRockyArid and pLatitude>fDesTop: pfallTerrain = choose( 66, etRockyMoist, etRockyArid )
elif pfallTerrain==etFlatArid and pLatitude>fDesTop: pfallTerrain = choose( 66, etFlatMoist, etFlatArid )
elif pfallTerrain==etFlatRainy and pLatitude>fDesBot and pLatitude<fDesTop: pfallTerrain = choose( 80, etFlatRainy, etFlatMoist )
elif pfallTerrain==etFlatPolar and pLatitude<fDesTop: pfallTerrain = choose( 80, etRockyMoist, etFlatMoist )
elif pfallTerrain==etFlatPolar and pLatitude<fTundra: pfallTerrain = choose( 80, etRockyMoist, etFlatPolar )
elif pfallTerrain==etFlatPolar and pLatitude<fSnow: pfallTerrain = choose( 66, etRockyMoist, etFlatPolar )
elif pfallTerrain==etRockyPolar and pLatitude<fTundra: pfallTerrain = etRockyMoist
elif pfallTerrain==etRockyPolar and pLatitude<fSnow: pfallTerrain = choose( 66, etFlatPolar, etRockyPolar )

Would my quick glance be correct that this reduce the chance that a certain terrain type occurs outside its normal climate zone? I'm not sure I would like such a reduction in variety. On the other hand, I haven't really noticed such a change in the maps I generated, so perhaps I'm misinterpreting this code.

***

A second big area where Planetfall is different from vanilla is plottype/peak/hills generation. That code wasnt written by me, and I don't understand the code at all. The effect and intention of it however is to create clusters/clumps of highlands/hills at times surrounded by ridges/peaks, to create areas where a Terraforming or anti-Planet ecological strategy is much more viable. This doesn't seem to happen at all in the maps generated with your MSTools. While there are more highlands, they seem to be distributed completely at random. So I have the usual questions: are you aware of the differences, are you aware of what the goal was of Planetfall's original code, etcetera?

***

Trenches: here it may just be my imagination based on limited tests, but I get the impression there are less of them. Could this code be responsible?:

# try to avoid inland trenches or shelves
if numWaterNeighbors(x, y, 1) < 5: continue
if numWaterNeighbors(x, y, 2) < 13: continue

***

I'm wondering if the various MapPrettifier functions are applied to Planetfall as well. Some shouldn't.

deIcifyEdges: this isn't necessary. Unlike in vanilla Civ, plots with Ice can provide a yield.

hillifyCoast: Undesired, Once again, Peak/Ridges provide a yield in Planetfall and can be walked upon, so there's no danger to having Ridges on the coast. Edit: Oh wait, I just noticed this function immediately returns for Planetfall. :)

lumpifyTerrain: matter of taste I guess. Don't really see the need.

I do like bulkifyIslands.

Some/all of the special map regions (except for the Command Center isle I've seen) seem to have names that fit more for the FfH universe. Is it intended those also appear on Planetfall maps?

***

BonusBalancer

Planetfall placed around 11 of each bonus resource on the map, regardless of map size. So in theory there's about one resource for each faction in the game (original seven + SMAX4). The generic Nutrient/Mineral/Energy Bonus resources are used to balance starting positions, and to randomly dot the map with a resource every x tiles regardless of the amount of players. Using vanilla bonus balancing code or vanilla normalizeAddExtras functions would ruin this goal. So I hope this code isn't used for maps generated for Planetfall.

In fact, except for Planetfall's own normalizeAddExtras function in the SDK (which only places the three generic nutrient/mineral/energy), none of the normalizestartingposition functions should be used. The idea behind Planetfall's starting positions is to have a much wider variety of starting positions than you encounter in vanilla (where everything is equalized), but to offer more tech strategies to make the most out of your starting position. For instance if you start surrounded with Jungle, you can go Terraformed. If you are surrounded by Fungus, you can go Hybrid. If you are surrounded by arid terrain without a river in sight, Biodomed is the way to go.

So for all Planetfall mapscripts, the following should be used:

def normalizeAddRiver():
return None

def normalizeRemovePeaks():
return None

def normalizeAddLakes():
return None

def normalizeRemoveBadFeatures():
return None

def normalizeRemoveBadTerrain():
return None

def normalizeAddFoodBonuses():
return None

def normalizeAddGoodTerrain():
return None

Else all Ridges, Jungle, Xenofungus for instance might be removed, because the game thinks those are bad terrain.

***

Another thing I noticed was that on a SmartMap, the starting positions were all over the place, rather than concentrated the Planetfall way.

That's what I noticed so far. I hope you can answer my questions. I'm looking forward to being able to play with a bigger variety of Planetfall-compatible mapscripts than the single one I currently have. :)

Temudjin
Jul 19, 2010, 04:50 AM
Thanks for the detailed analysys, obviously there is more to the planet of 'Planetfall' than I realized.


It says:


elif eTerrain==itTundra: pfallTerrain = choose( 66, etRockyMoist, etFlatPolar )

In Planetfall's CvMapGeneratorUtil, Tundra gets changed to 33% Flat Polar, 33% Flat Moist, 16% Rocky Moist and 16% Rocky Polar. What is the reason behind this difference?
Also what does this code do?



if pfallTerrain==etRockyArid and pLatitude<fDesBot: pfallTerrain = choose( 66, etRockyMoist, etRockyArid )
elif pfallTerrain==etFlatArid and pLatitude<fDesBot: pfallTerrain = choose( 66, etFlatMoist, etFlatArid )
elif pfallTerrain==etRockyArid and pLatitude>fDesTop: pfallTerrain = choose( 66, etRockyMoist, etRockyArid )
elif pfallTerrain==etFlatArid and pLatitude>fDesTop: pfallTerrain = choose( 66, etFlatMoist, etFlatArid )
elif pfallTerrain==etFlatRainy and pLatitude>fDesBot and pLatitude<fDesTop: pfallTerrain = choose( 80, etFlatRainy, etFlatMoist )
elif pfallTerrain==etFlatPolar and pLatitude<fDesTop: pfallTerrain = choose( 80, etRockyMoist, etFlatMoist )
elif pfallTerrain==etFlatPolar and pLatitude<fTundra: pfallTerrain = choose( 80, etRockyMoist, etFlatPolar )
elif pfallTerrain==etFlatPolar and pLatitude<fSnow: pfallTerrain = choose( 66, etRockyMoist, etFlatPolar )
elif pfallTerrain==etRockyPolar and pLatitude<fTundra: pfallTerrain = etRockyMoist
elif pfallTerrain==etRockyPolar and pLatitude<fSnow: pfallTerrain = choose( 66, etFlatPolar, etRockyPolar )

Would my quick glance be correct that this reduce the chance that a certain terrain type occurs outside its normal climate zone? I'm not sure I would like such a reduction in variety. On the other hand, I haven't really noticed such a change in the maps I generated, so perhaps I'm misinterpreting this code.

I've had to project 6 different land-terrains into 8 and choose a randomizing yet somewhat self-adjusting process.
First: Desert,Plains,Grass and Snow and had corresponding terrain (Arid Moist,Rainy,Polar) and i gave the flat version a 66% chance. Marsh had also a pretty obvious corresponding terrain (FlatRainy) no variance needed here. Tundra was the odd one out and I gave it a 66% chance for RockyMoist and a 33% chance to be FlatPolar (Somehow I visualize tundra more moist than rainy).
Second: Depending on the latitude I gave the new terrain a chance to be more or less damp or hot. My coldness sequence is RockyMoist, FlatPolar, RockyPolar.
Indeed my idea was to give neighboring terrains a slightly bigger chance to be similar and climatically more reasonable, the effect shouldn't be all that big though.


A second big area where Planetfall is different from vanilla is plottype/peak/hills generation. That code wasnt written by me, and I don't understand the code at all. The effect and intention of it however is to create clusters/clumps of highlands/hills at times surrounded by ridges/peaks, to create areas where a Terraforming or anti-Planet ecological strategy is much more viable. This doesn't seem to happen at all in the maps generated with your MSTools. While there are more highlands, they seem to be distributed completely at random. So I have the usual questions: are you aware of the differences, are you aware of what the goal was of Planetfall's original code, etcetera?

Actually I noticed this myself and wrote planetFallMap.buildPfallHighlands(), which adds foothills and highlands near already existing hills/peaks, to adjust for the problem. But it seems I have underestimated the prominence of hills/peaks on planetfall. Basically I will have to adjust the chance to convert considerably upwards and may need to lumpify the hills a bit.


Trenches: here it may just be my imagination based on limited tests, but I get the impression there are less of them. Could this code be responsible?:


# try to avoid inland trenches or shelves
if numWaterNeighbors(x, y, 1) < 5: continue
if numWaterNeighbors(x, y, 2) < 13: continue


Indeed it is. The problem isn't trivial though as MST is supposed to work for all types of maps, some of them have inland seas which are to small to reasonably have trenches. The above code was a quick fix for that, but you are right that it may be a bit to restrictive. Perhaps I just ignore the retriction on the biggest ocean.


deIcifyEdges: this isn't necessary. Unlike in vanilla Civ, plots with Ice can provide a yield.

While not exactly necessary, deIcifyEdges() still seems to be a good idea, as some map-scripts take care to manipulate latitudes to simulate the warmer climate of a restricted region.


Some/all of the special map regions (except for the Command Center isle I've seen) seem to have names that fit more for the FfH universe. Is it intended those also appear on Planetfall maps?

Personally I think it's perfectly reasonable to give a peak a name like 'Wizards Hat' even on an alien world, but I'll probably give an extra parameter to getModInfo() to allow suppression of region-names (May be a good idea for FFH too, if the mod option for using all unique features is activated). You can do this right now by putting


mst.mapRegions.initialize( noSigns=True )

right after your call to getModInfo(). Sorry I forgot to mention this in the API.
Actually I could use some ideas for Planetfall special region names.


BonusBalancer

Planetfall placed around 11 of each bonus resource on the map, regardless of map size. So in theory there's about one resource for each faction in the game (original seven + SMAX4). The generic Nutrient/Mineral/Energy Bonus resources are used to balance starting positions, and to randomly dot the map with a resource every x tiles regardless of the amount of players. Using vanilla bonus balancing code or vanilla normalizeAddExtras functions would ruin this goal. So I hope this code isn't used for maps generated for Planetfall.

I didn't realize that and will disallow bonus-balancing and missing-boni-giving for Planetfall.


In fact, except for Planetfall's own normalizeAddExtras function in the SDK (which only places the three generic nutrient/mineral/energy), none of the normalizestartingposition functions should be used. The idea behind Planetfall's starting positions is to have a much wider variety of starting positions than you encounter in vanilla (where everything is equalized), but to offer more tech strategies to make the most out of your starting position. For instance if you start surrounded with Jungle, you can go Terraformed. If you are surrounded by Fungus, you can go Hybrid. If you are surrounded by arid terrain without a river in sight, Biodomed is the way to go.

So for all Planetfall mapscripts, the following should be used:


def normalizeAddRiver():
return None
def normalizeRemovePeaks():
return None
def normalizeAddLakes():
return None
def normalizeRemoveBadFeatures():
return None
def normalizeRemoveBadTerrain():
return None
def normalizeAddFoodBonuses():
return None
def normalizeAddGoodTerrain():
return None

Else all Ridges, Jungle, Xenofungus for instance might be removed, because the game thinks those are bad terrain.

I didn't realize that either and will change the maps accordingly.


Another thing I noticed was that on a SmartMap, the starting positions were all over the place, rather than concentrated the Planetfall way.

I've seen this too (now), not only in SmartMap. The first thing I do in assignStartingPlots() is test for Planetfall and then use the default procedure. I'm a bit out of my depth here.

Maniac
Jul 19, 2010, 12:34 PM
I've had to project 6 different land-terrains into 8 and choose a randomizing yet somewhat self-adjusting process.

But why did you not do Tundra like Planetfall's MapGeneratorUtil does it? Is the difference intentional, or were you not aware of the code in MapGeneratorUtil?

Would you be willing to tell me the line(s) of code to add to MST to convert Tundra the way Planetfall currently does it?

Is (virtual) Marsh terrain actually generated for Planetfall maps?

Actually I noticed this myself and wrote planetFallMap.buildPfallHighlands(), which adds foothills and highlands near already existing hills/peaks, to adjust for the problem. But it seems I have underestimated the prominence of hills/peaks on planetfall. Basically I will have to adjust the chance to convert considerably upwards and may need to lumpify the hills a bit.

If your goal is to generate highlands in MST as Planetfall currently does it (is it?), is it not possible to copy Planetfall's code as close as possible to MST?

While not exactly necessary, deIcifyEdges() still seems to be a good idea, as some map-scripts take care to manipulate latitudes to simulate the warmer climate of a restricted region.

Not sure I understand this sentence. Do you mean this code does not have an effect on mapscripts that do not change latitudes?

Actually I could use some ideas for Planetfall special region names.

SMAC's Map of Planet has many landmark names. IIRC no mountains though except for Mount Planet. Do you own SMAC and/or are familiar with the Map of Planet?

Some of SMAC's landmarks are added through SDK code. There are some landmarks which I haven't implemented because they'd need to span over multiple plots and I don't really know a good way to do that. You however seem to have the skills.

Some ideas:

Geothermal Shallows. In the handdrawn Map of Planet for Planetfall, this sea region is represented by a mix of shelf and coast terrain with some Hydrothermal Vent and Energy Bonus resources on it.

Fossil Field Ridge: sea area with some Oil and Mineral resources. On Planetfall's Map of Planet, IIRC it's Trench feature and more than one plot wide (instead of the usual single-plot-wide trench line)

Sargasso Sea: sea region, a concentration of sea fungus with four sea unity pods in the middle.

Freshwater Sea: a somewhat round inland lake, totally Shelf with some Nutrient bonus resources.

Temudjin
Jul 19, 2010, 05:41 PM
But why did you not do Tundra like Planetfall's MapGeneratorUtil does it? Is the difference intentional, or were you not aware of the code in MapGeneratorUtil?

Would you be willing to tell me the line(s) of code to add to MST to convert Tundra the way Planetfall currently does it?

I did have a look, but only a cursory one, which apparently didn't extend to figuring out tundra (that was more than a year ago). Do you mean the transformation should be: 50% FlatPolar, 25% RockyPolar, 25% FlatMoist ? I guess I could do that.
The code is in mapPfallTerrain() lines 2090+ which you already found. Just change:


elif eTerrain==itTundra: pfallTerrain = choose( 66, etRockyMoist, etFlatPolar )

to

elif eTerrain==itTundra: pfallTerrain = chooseMore( (50,etFlatPolar), (75,RockyPolar), (100,etFlatMoist) )


But this code is only used by Erebus and PerfectWorld, which themselves produce terrain-lists outside their terrain-generator. The other maps use the Planetfall terrain-generator, mostly via mst.MST_TerrainGenerator().


Is (virtual) Marsh terrain actually generated for Planetfall maps?

Actually no it isn't by MST. But other map-scripts may have generated marshes before the terrain is converted by mst.planetFallMap.mapPfallTerrain().


If your goal is to generate highlands in MST as Planetfall currently does it (is it?), is it not possible to copy Planetfall's code as close as possible to MST?

Good question :confused:. Upon consideration I guess I want to create those ridges and highlands of Planetfall as they are a vital part of the Planetfall gameplay, but I don't think I'd want to go quite as far with them. Ideally I'd want to retain at least the general theme of the other map-scripts. Which of course means I'm not going to copy Planetfall's code (which I don't quite understand either).


While not exactly necessary, deIcifyEdges() still seems to be a good idea, as some map-scripts take care to manipulate latitudes to simulate the warmer climate of a restricted region.
Not sure I understand this sentence. Do you mean this code does not have an effect on mapscripts that do not change latitudes?


mst.mapPrettifier.deIcifyEdges( iLat=66, addToroidIce=True ) will only remove ice, if the highest (or lowest) latitude of the map is smaller than iLat. Additionally it may add a girdle of ice on toroid worlds.


SMAC's Map of Planet has many landmark names. IIRC no mountains though except for Mount Planet. Do you own SMAC and/or are familiar with the Map of Planet?

Some of SMAC's landmarks are added through SDK code. There are some landmarks which I haven't implemented because they'd need to span over multiple plots and I don't really know a good way to do that. You however seem to have the skills.

Some ideas:

Geothermal Shallows. In the handdrawn Map of Planet for Planetfall, this sea region is represented by a mix of shelf and coast terrain with some Hydrothermal Vent and Energy Bonus resources on it.

Fossil Field Ridge: sea area with some Oil and Mineral resources. On Planetfall's Map of Planet, IIRC it's Trench feature and more than one plot wide (instead of the usual single-plot-wide trench line)

Sargasso Sea: sea region, a concentration of sea fungus with four sea unity pods in the middle.

Freshwater Sea: a somewhat round inland lake, totally Shelf with some Nutrient bonus resources.


Yes I did own SMAC and probably still do somewhere :lol:. But I've never had the extension and I didn't read manuals much, so I have no idea about the 'Map of Planet'.

Thanks, I may use one or two of those ideas to make new special regions for Planetfall. Not Sargasso Sea though, as there would be units involved and I'll avoid that (for now).

Any ideas for additional names for known special regions whould be very welcome indeed:
- For BigDent I use 5 different names (Volcano isn't needed for Planetfall) depending on the plot in the middle like:

{
'Volcano': "Hole of the World",
'Peak': "The Big Dent",
'Flat': "Hammers Rest",
'Water': "Hole of the World",
'Hills': "Big Dent Highlands"
}

- For LostIsle I have only


lostIsleNames_Pfall = [ "Alien HQ", "Command Center", "City of Light", "Atlantis Command" ]

Temudjin
Jul 20, 2010, 05:26 AM
@ Maniac:
I couldn't find a solution for the 'Scattered Pods' problem yet. But having checked on my end, I've snooped a bit on yours and found an oddity:

bool CvPlayer::startingPlotWithinRange(CvPlot* pPlot, PlayerTypes ePlayer, int iRange, int iPass) const in CvPlayer.cpp always returns false.
This function is called by findStartingPlot(playerID, validFn = None) in CvMapGeneratorUtil.py
which in turn is called by void CvGame::assignStartingPlots() in CvGame.cpp
which is the main function for creating starting-plots.

I'm not entirely sure if that's the source of the problem, but that may well be the case.
The MST map-scripts either don't have assignStartingPlots() or call CyPythonMgr().allowDefaultImpl() if the Planetfall mod is active.

Edit: I've just noticed that Earth3 and SeaHighlands use their own starting-plot finders with Planetfall. I may change that for SeaHighlands, but probably not for Earth3.

Maniac
Jul 20, 2010, 02:00 PM
I did have a look, but only a cursory one, which apparently didn't extend to figuring out tundra (that was more than a year ago). Do you mean the transformation should be: 50% FlatPolar, 25% RockyPolar, 25% FlatMoist ? I guess I could do that.

In Planetfall's CvMapGeneratorUtil, Tundra gets changed to 33% Flat Polar, 33% Flat Moist, 16% Rocky Moist and 16% Rocky Polar.

The code is in mapPfallTerrain() lines 2090+ which you already found. Just change:

Thanks! :D

Good question :confused:. Upon consideration I guess I want to create those ridges and highlands of Planetfall as they are a vital part of the Planetfall gameplay, but I don't think I'd want to go quite as far with them. Ideally I'd want to retain at least the general theme of the other map-scripts. Which of course means I'm not going to copy Planetfall's code (which I don't quite understand either).

I certainly agree that not all mapscripts should follow the Planetfall highland generation, though I do think it would be nice to have it as an option in SmartMap for instance. I'll have another look if I can figure out the highlands code myself.

Thanks, I may use one or two of those ideas to make new special regions for Planetfall. Not Sargasso Sea though, as there would be units involved and I'll avoid that (for now).

The sea unity pods aren't units, but IMPROVEMENT_UNITY_POD_SEA. And I was mistaken about the name :mischief: - it's called New Sargasso.

Any ideas for additional names for known special regions whould be very welcome indeed:

What is the Big Dent?

If you'd like more landmark names, rather than given an exhaustive list of all landmark names in SMAC, it might be easier for both of us if you downloaded the SMAC demo (http://firaxis.com/games/game_detail.php?gameid=7&showcon=2), a mere 20 MB. Then place and extract the attached saves in "Sid Meier's Alpha Centauri's Demo" to have a look at the Map of Planet.

For LostIsle I have only

Perhaps the Isle of Dexamenus/Mnemi*ache (spelling probably incorrect) can be used here.

I couldn't find a solution for the 'Scattered Pods' problem yet. But having checked on my end, I've snooped a bit on yours and found an oddity:

That also returns false in vanilla. This is the function:

bool CvPlayer::startingPlotWithinRange(CvPlot* pPlot, PlayerTypes ePlayer, int iRange, int iPass) const
{
PROFILE_FUNC();

//XXX changes to AI_foundValue (which are far more flexible) make this function
// redundant but it is still called from Python.
return false;
}

I haven't looked deeper into this issue myself, but perhaps the key might be figuring out the difference between the MST mapscripts and Planetfall's original mapscript, where starting positions do work fine.

Maniac
Jul 20, 2010, 03:23 PM
Which of course means I'm not going to copy Planetfall's code (which I don't quite understand either).

I'm not sure if your problem was the same as mine, but in the past I stared myself blind on the PFHL_MultilayeredFractal() class, assuming the code responsible for highland creation was somewhere in there. Now I've looked at it again however, I see that class is only responsible for the distinction between land and water, and that hills and peaks are added afterwards:

def generatePlotTypes():
NiTextOut("Setting Plot Types (Python PlanetFall Highlands) ...")

gc = CyGlobalContext()
map = CyMap()
dice = gc.getGame().getMapRand()
iW = map.getGridWidth()
iH = map.getGridHeight()
plotTypes = [PlotTypes.PLOT_OCEAN] * (iW*iH)
terrainFrac = CyFractal()

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

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

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

return plotTypes

I believe the only possible difficulty with getting this code to work for other mapscripts is making sure all land plots are PLOT_LAND (ie, flatland) in the plotTypes array before the "main loop" is run.

Maniac
Jul 20, 2010, 04:27 PM
As an exercise to see if I understand Planetfall's highland generation, I'd like to make the Pangaea usable for Planetfall.

I barely understand Pangaea (I don't understand any mapscript well for that matter), but I think in that mapscript generateTerrainTypes() is the place to add hills and peaks. First stumbling block: to get Planetfall's highland code to work, I need an array of what plottypes the plots are at that point. How can I get that inside generateTerrainTypes()??

Edit: Never mind. In SmartMap, the hills and peak are generated in generatePlotTypes.

Temudjin
Jul 23, 2010, 04:42 AM
In Planetfall's CvMapGeneratorUtil, Tundra gets changed to 33% Flat Polar, 33% Flat Moist, 16% Rocky Moist and 16% Rocky Polar.

Yes, I've got that wrong. I'll change that in planetFallMap.mapPfallTerrain().


I certainly agree that not all mapscripts should follow the Planetfall highland generation, though I do think it would be nice to have it as an option in SmartMap for instance. I'll have another look if I can figure out the highlands code myself.

Sorry no option (yet), but I've upgraded the highland code in planetFallMap.buildPfallHighlands(), which now produces more additional hills/peaks in more clustered ranges. The Land/Hills and Land/Peaks percentages should now be comparable to your own Planetfall map.


The sea unity pods aren't units, but IMPROVEMENT_UNITY_POD_SEA. And I was mistaken about the name - it's called New Sargasso.

Thanks - I'll look into it. Also at the Demo.
Do you mind if I give your great dunes a name? I thought 'The Great Dunes", but only once and only if there are at least three tiles of them together.


What is the Big Dent?

A mountain range. In Earth3.py I use a single BigDent special region to simulate the Himalayas.


I couldn't find a solution for the 'Scattered Pods' problem yet. But having checked on my end, I've snooped a bit on yours and found an oddity:
That also returns false in vanilla. This is the function:

Though not in Vanilla or Warlords, but it does indeed in BtS. This is strange as that potentially breaks the findStartingPlot() function in CvMapGeneratorUtil.py, since the minimum distance to other starting-plots is not tested anymore. Several map-scripts call that function. It may be an issue for the unofficial patch.

:goodjob:Finally I've run the 'Scattered Pods' problem to the ground. It seems that in assignStartingPlots() or findStartingPlot() the following code:


def assignStartingPlots():
if mst.bPfall:
CyPythonMgr().allowDefaultImpl()
else:
... other code

def nextFunction():


has not the same results as:

def assignStartingPlots():
if mst.bPfall:
CyPythonMgr().allowDefaultImpl()
return
... other code

def nextFunction():


sadly only the first version will take the 'Scattered Landing Pods' option into account and I'll have to adjust for that.


Now I've looked at it again however, I see that class is only responsible for the distinction between land and water, and that hills and peaks are added afterward:
..
I believe the only possible difficulty with getting this code to work for other map-scripts is making sure all land plots are PLOT_LAND (ie, flatland) in the plotTypes array before the "main loop" is run.

You're probably right. And it's indeed the fractals that look odd to me.
My point was however that some scripts take more care building their landscape and their terrain than others, and I'd like to preserve that. On the other hand I already mostly use the Planetfall terrain-generator regardless and generally adjust things a lot. On the gripping hand, I'll probably try and put an option into Tectonics and look if/how it works.

Temudjin
Jul 23, 2010, 08:02 AM
On the gripping hand, I'll probably try and put an option into Tectonics and look if/how it works.

That was actually easier than I thought, although I used the brute force approach here.

I've just copied PFHL_MultilayeredFractal(), generatePlotTypes() {renaming the function, adding the plotTypes parameter/result and commenting out only two lines }, and a few global constants from planetfall.py.
Then I inserted a call before the end of the original generatePlotTypes() before the plotTypes where returned thus changing aforementioned plotTypes.

So at least Tectonics_mst.py will have a new option, whether to use the original Planetfall Highlands generator or the plot adjustment approach with planetFallMap.buildPfallHighlands().

Afforess
Jul 23, 2010, 02:32 PM
Temudjin, I like how your mapscript tools enable the Erebus Mapscript for normal BTS games. I was wondering, what would it take to convert the ErebusContinents mapscript? I'm not exactly familiar with how mapscripts work; what is the conversion process?

Maniac
Jul 24, 2010, 08:52 AM
Thanks - I'll look into it. Also at the Demo.
Do you mind if I give your great dunes a name? I thought 'The Great Dunes", but only once and only if there are at least three tiles of them together.

Do you mean to give it a sign on the map? This is just a personal preference and probably a minority view, but I'm not really fond of signs on the map, as they obstruct my view of the plot just north of the plot with the sign. People can already see it's the Great Dunes by hovering their mouse over the feature.

By the way, I'm wondering if you can think of a better (and still fast) way to determine a good location for the Great Dunes. Currently I have this in the SDK:

int iDunes = 0;
int* piShuffle6 = shuffle(GC.getMapINLINE().numPlotsINLINE(), GC.getGameINLINE().getMapRand());
for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
{
pPlot = GC.getMapINLINE().plotByIndexINLINE(piShuffle6[iI]);
iDunes = 0;
if (pPlot->canHaveFeature((FeatureTypes)GC.getInfoTypeForStri ng(GC.getDefineSTRING("FEATURE_DUNES"))))
{
for (int iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
{
pAdjacentPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iJ));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->canHaveFeature((FeatureTypes)GC.getInfoTypeForStri ng(GC.getDefineSTRING("FEATURE_DUNES"))))
{
if (iDunes == 0)
{
pPlot->setFeatureType((FeatureTypes)GC.getInfoTypeForStri ng(GC.getDefineSTRING("FEATURE_DUNES")));
}
pAdjacentPlot->setFeatureType((FeatureTypes)GC.getInfoTypeForStri ng(GC.getDefineSTRING("FEATURE_DUNES")));
iDunes++;
}
}
}
}
if (iDunes > 0)
{
break;
}
}
SAFE_DELETE_ARRAY(piShuffle6);

This often results in 'Great Dunes" of only three plots. I'd prefer for the Great Dunes to exist in the greatest extension of arid terrain on the map, and then for the Great Dunes to possible stretch over more than at most a 9 plot square.

A mountain range. In Earth3.py I use a single BigDent special region to simulate the Himalayas.

In that case I don't think the landmark will be very noticable in Planetfall, considering Planetfall is already supposed to have large plateaus of highland bordered by a "mountain ridge" of walkable Ridges/Peaks. At least I didn't recognize what it was supposed to be while test-generating various maps.

Finally I've run the 'Scattered Pods' problem to the ground. It seems that in assignStartingPlots() or findStartingPlot() the following code:

For the record, personally I think it's ok if the Scattered Landing Pods option uses starting plot code of the mapscript rather than what the Planetfall SDK would produce (except for the startingplot normalization code which should still not be used). Does this mean, if I understand things correctly, this is the code-way to go?;

def assignStartingPlots():
if mst.bPfall and not bScatteredLandingPods:
CyPythonMgr().allowDefaultImpl()
return
else:
... other code

On the gripping hand

What do you mean by 'gripping hand'?

I've just copied PFHL_MultilayeredFractal(), generatePlotTypes() {renaming the function, adding the plotTypes parameter/result and commenting out only two lines }, and a few global constants from planetfall.py.
Then I inserted a call before the end of the original generatePlotTypes() before the plotTypes where returned thus changing aforementioned plotTypes.

So at least Tectonics_mst.py will have a new option, whether to use the original Planetfall Highlands generator or the plot adjustment approach with planetFallMap.buildPfallHighlands().

I don't understand why you copied PFHL_MultilayeredFractal() if the goal was only to get the Planetfall highland generation rather than also the land/water generation. :confused:

Anyway, I'd like to try and add the highland generation code to SmartMap? Could you please attach any files you have modified in the meantime? I figure I might as well make the modifications on the most up to date files you have.

Baleur
Aug 01, 2010, 04:54 AM
I'm very split on these maps...
I love the idea of unique locations even in BUG games, such as the mountain clusters, atlantis-ruins and various lakes and stuff. But they also have a bad side, they make every map seem the same.. When every map you generate has a mountain cluster and a dark lake, it defeats the purpose of most of these great mapscripts (such as perfectworld2, planet generator even though you didnt tweak that one yet, tectonics etc).

I mean, i love what you are trying to do here, and i suppose the main thing was making mod-compatability.
But i find myself regenerating the maps and seeing the same map, with the same locations just in different places.

OnmyojiOmn
Dec 05, 2010, 04:23 AM
Nobody should be using PerfectWorld2 when there's PerfectWorld2f. I updated it for your script so I could use it with FFH. It seems to work pretty well.

Temudjin
Mar 16, 2011, 11:38 AM
Sorry for my long absence, but much to my chagrin there was something called 'Real Live' which interfered :( and then there was (still is..) Civ5 - the final answer to modding :rolleyes:.

@Maniac:
What do you mean by 'gripping hand'?
See: 'The Mote in God's Eye' 1974 by Larry Niven (w/J. Pournelle) and the sequel 'The Gripping Hand' 1993 - 'Ringworld' is also by Larry Niven.

@Baleur:
I try my best to randomise those special locations as much as reasonable. In the end it's not to hard to just reduce the number of appearances (or the probability of their appearance) or comment them out.
The calls are found in: addRivers(), addFeatures() and normalizeStartingPlotLocations()

@OnmyojiOmn:
Thanks. I incorporated your changes into PerfectWorld_206f1_mst.py
I've also converted PerfectMongoose, which also has Fuyus balancing.

Xyth
Jun 26, 2011, 09:49 PM
I don't know if this is still in development or not but I recently discovered it and would like to try integrate it into my mod. I use a Mac and unfortunately it's throwing some errors. I'm initially trying it with just Tectonics_316a_mst.py (in /Mods/<modname>/PrivateMaps/) and MapScriptTools.py (in /Mods/<modname>/Assets/Python/). This is the error on mod launch:

Traceback (most recent call last):

File "<string>", line 1, in ?

File "<string>", line 52, in load_module

File "Tectonics_316a_mst", line 117, in ?

File "<string>", line 52, in load_module

File "MapScriptTools", line 2205, in ?

File "MapScriptTools", line 2037, in __init__

File "MapScriptTools", line 2126, in getCivPaths

NameError: global name 'join' is not defined
Failed to load python module Tectonics_316a_mst.
ERR: Call function getNumHiddenCustomMapOptions failed. Can't find module Tectonics_316a_mst
ERR: Call function getNumCustomMapOptions failed. Can't find module Tectonics_316a_mst
ERR: Call function getNumHiddenCustomMapOptions failed. Can't find module Tectonics_316a_mst
ERR: Call function getNumCustomMapOptions failed. Can't find module Tectonics_316a_mst
ERR: Call function getNumHiddenCustomMapOptions failed. Can't find module Tectonics_316a_mst
ERR: Call function getNumCustomMapOptions failed. Can't find module Tectonics_316a_mst

Looking at the getCivPaths procedure it seems 'join' isn't meant to be a variable at all - is it a Python 2.4 command? (Assuming I'm interpreting this all correctly). If so, is there some way of making it Python 2.3 compatible like there was for 'set'?

EmperorFool
Jun 30, 2011, 01:07 AM
Edit: Ignore the below. There's a simple error on line 2126. Insert the bold "os.path." before "join".


self.rootDir = os.path.join( self.userDir, "Civilization IV " + self.appName )


I don't have the code in front of me, so post the line that uses join() along with some surrounding context. It should be easy to write a quick function to do what join() does. The following is without looking anything up, and it's been a while since I did any Python:


if "join" not in string.__dict__:
def join(self, items):
if not items:
return ""
else:
joined = ""
for item in items:
joined += self + item
return joined[len(self):]
string.join = join


Looking at the 2.3 documentation (http://docs.python.org/release/2.3/lib/module-string.html), it looks like the string module has a join() function, and the string class has a join() method. So I don't know why this doesn't work. I need to see the code.

Xyth
Jun 30, 2011, 09:28 PM
Edit: Ignore the below. There's a simple error on line 2126. Insert the bold "os.path." before "join".

Thanks, that cleared that up. I'm now getting some errors in individual mapscripts related to 'set()' but I'm guessing I can clear those up by copying the code you suggested earlier from MapScriptTools.py. Others seem to be working fine now though. Cheers!

dommain
Jul 03, 2011, 06:23 PM
The Master of Mana (aka. Wild Mana) mod doesn't work under the FFH like it should. It doesn't produce any unique landmarks except for 1 (randomly assigned to a hut).

LunarMongoose
Jul 05, 2011, 01:31 AM
First time I've looked at this thread; wow, not bad, Temudjin! :) :) :)

This definitely opens up the option of putting more custom maps in my mod. I'm also very interested in: Deep Ocean and Trenches (though I'm sure Maniac will kill me if I steal any more stuff from Planetfall lol, plus I have to like the graphics for em, which I vaguely remember looking at a long time ago); bigger coasts if that means what I'm assuming it does; and your new river code (even though you weren't able to add it to PW/PM).

I would tend to not want to mess with starting location placement, move or hillify resources, merge small islands, or add an Atlantis-type island, but I'm intrigued by the Big Bog idea, hehe.

Anyway, I'll definitely be taking a close look at this when I have time... thanks for making it!

And
Jul 07, 2011, 03:38 AM
Good Morning,
I have a simple question. Playing BtS, where do I have to put the maps (*.py files)? In the Public Maps under the Civ4 folder? Or into Public Maps under the BtS folder? Or in the Public Maps under the My Games etc etc folder?
I searched for an answer but I only got infos related to pre-BtS games. It's possible that I didn't search well enough of course :)
Thanks in advance!

EmperorFool
Jul 09, 2011, 06:50 PM
Put them in any BTS PublicMaps folder--either where you installed BTS or in My Games / Beyond the Sword. The latter is created by BTS to hold user-created stuff such as saved games, screen shots, custom maps, mods, etc. The install location works too but is sometimes not writable by a non-Administrator user.

And
Jul 11, 2011, 02:36 AM
Thank you very much!

Xyth
Jul 22, 2011, 11:10 PM
I'm still tinkering with this to get it to run on Mac. One error I'm getting is related to sort(). Basically there are a few instances in the main file where sort() has something in the brackets. One example:

vList = dict.values()
vList.sort( key = lambda test: len(test[1]) )
vList.reverse()

These are causing Python exceptions, though everything still seems to function properly. I have no idea what the bit in the brackets does, removing it (changing each occurrence to .sort()) seems to have no ill effect but I thought I should ask just in case.

EmperorFool
Jul 23, 2011, 03:53 AM
It provides a different method for sorting. It looks like the items in the list are themselves lists with at least two elements. The above sorts the list items by the length of their second elements. I think you could achieve the same effect manually.


vList = [(len(x[1]), x) for x in dict.values()]
vList.sort()
vList.reverse()
vList = [x for _, x in vList]

Temudjin
Jul 23, 2011, 05:31 AM
Oops!:cringe: Mostly doing Civ5 now, I didn't realize my thread became active again.
Many thanks EmperorFool for answering questions and resolving errors in my absence.

The 'key' keyword parameter in the sort() method for lists was also new in Python 2.4.
The old-fashioned way to write:
vList.sort( key = lambda test: len(test[1]) )
would be:
vList.sort( cmp=lambda x,y: cmp( len(x[1]), len(y[1]) ) )
I've used this only in makeMapLegend() and showContinents(). The changes should be fairly straightforward.

Thanks Xyth for trying out the MapScriptTools and not giving up after finding some errors. I am still interested in getting my MapScriptTools right for the MAC, so I'll probably post a version 1.02, if I can get some confirmation on the solution.

Temudjin
Jul 24, 2011, 05:26 AM
@dommain:
I'm not quite certain if I understand what you mean, but the landmarks in FFH are the names of special improvements on a single tile, while the 'landmarks' in MST are the names of the special regions (several tiles) generated by MST. They tend to be near the middle of that region.
How many of those regions exist, depends on the map and it's size.

@LunarMongoose:
Thanks. I'm not altogether sure I'd always want Atlantis and the Elemental Quarter myself; that's one reason I introduced some uncertainty (adjustable by the map-script) for these features to actually exist on a particular map.

Baldyr
Jul 24, 2011, 06:49 AM
vList = [(len(x[1]), x) for x in dict.values()]
vList.sort()
vList.reverse()
vList = [x for _, x in vList]

Man, this is one of those cases where I just can't make heads or tails of a piece of code. Could you, perhaps, run this script through line by line? Probably start with what the names x and dict are referring to. And what the resulting vList array would look like. Please?

EmperorFool
Jul 24, 2011, 12:04 PM
vList = [(len(x[1]), x) for x in dict.values()]
vList.sort()
vList.reverse()
vList = [x for _, x in vList]

Putting a loop inside a pair of square brackets as on the first line is called a list comprehension and builds a list from the values from the loop. "dict" is from the original code and I assume the name of a local variable which is actually a very bad idea because it hides the name of the dict() global function. "dict.values()" pulls all of the values without their keys from said dictionary. So "for x in dict.values()" loops over each value in "dict" and puts each one into a variable named "x" which you can use.

This value "x" is used to pull the second element x[1] from it, assuming it's a tuple, and calculates its length. It packs the length and the tuple x into a new tuple as the element to place into the new list. Now vList is a list of two-element tuples where the first element is the length of one of the elements contained in the second element. :)


(2, (4, "hi"))
(3, (21, "bye"))
...


That's just an example of what could be contained in there.

The sort() and reverse() lines should be self-explanatory. If not, use Google. :p

The final line uses another list comprehension to extract the original dictionary values from the vList elements. It loops over the list and assigns the elements one-by-one to _ and x. In Python _ is the universal "I don't care about this value" variable. It's a normal variable, but people use it by convention to signify to the reader that they aren't going to use it. Assigning a list to multiple variables with one assignment "_, x = ..." breaks up the tuple/list so each variable holds a single element.

So this code loops over the two-element tuples, grabs the second element into x, and puts those into a new list.

Xyth
Jul 24, 2011, 09:57 PM
Looks the Mac implementation of Python won't accept anything inside the brackets of .sort():

TypeError: sort() takes no keyword arguments

That's the same error for both the original code and 'the old-fashioned way'. EmperorFool's code seems to work though, at least no errors were thrown. I replaced the code around lines 8468, 8474, 8482, 8801 and 8803 (along with EmperorFool's fix for line 2126) and the main file seems to be working without problem.

I haven't tried every mapscript yet but the included Earth3, Inland Sea, Sea Highlands, and Tectonics works fine, as does using the template in the standard Archipelago.py. I know that Fractured World and a few others were throwing the same error as above but I'll try EmperorFool's fix on them and see if that solves it. I'll let you know how that goes when I get a chance.

Xyth
Jul 25, 2011, 12:10 AM
Actually I've just realized some of those lines weren't the same as the one I posted earlier:

if not (addLine == None):
aList = addLine
aList.sort( key = lambda test: len(test) )
aTab = len( aList[0] )


aList.sort( key = lambda test: test[18:26] )
aList.reverse()
wList.sort( key = lambda test: test[18:26] )
wList.reverse()

I confess that EmperorFool's explanation made my brain melt, how do I convert these two given they don't have any mention of dict.values()?

EmperorFool
Jul 25, 2011, 01:47 AM
I'll need more context around those lines to be sure. If aList from the first isn't used after that code, you can use this:


aList = [(len(x), x) for x in aList]
aList.sort()
aList = [x for _, x in aList]
aTab = len( aList[0] )


For the second block you can use the same pattern as the first: build a list combining the key and the value into elements, sort it, and break it apart again.


aList = [(len(x[18:26]), x) for x in aList]
aList.sort()
aList = [x for _, x in aList]

wList = [(len(x[18:26]), x) for x in wList]
wList.sort()
wList = [x for _, x in wList]


You might first try using the fix that Temudjin proposed but removing the name of the parameter. The error states that sort() doesn't take any namedparameters, but IIRC that is the case if the parameters don't have default values. Remove the name so it becomes a positional parameter.


vList.sort( lambda x,y: cmp( len(x[1]), len(y[1]) ) )

Xyth
Jul 25, 2011, 03:05 AM
You might first try using the fix that Temudjin proposed but removing the name of the parameter. The error states that sort() doesn't take any namedparameters, but IIRC that is the case if the parameters don't have default values. Remove the name so it becomes a positional parameter.


vList.sort( lambda x,y: cmp( len(x[1]), len(y[1]) ) )


Ah this seemed to work for each of the lines in question (I changed the bit in square brackets to match the original version of each). Thanks to you both!

Temudjin
Jul 25, 2011, 06:49 AM
Thanks again Xyth & EmperorFool.
The new scheme is now incorporated into MapScriptTools 1.02.
I've also changed FracturedWorld, Ringworld and SmartMap accordingly. They and the other maps should now also work on the MAC - I hope.

Publication will be soon. (Yeah, I've heard that one before. ;))

HardRocker
Jul 25, 2011, 04:47 PM
would this work with RFC when making a modcomp???

Xyth
Jul 26, 2011, 05:03 AM
Temudjin, I was wondering if I could make a request. I'm experimenting with reefs and was thinking I'd like it if reefs never appeared as single tiles but rather as 2-5 tiles in a rough line.

If you're too busy, I might have a go at trying to write it myself. Any tips on useful functions I could use to achieve this?

Temudjin
Jul 29, 2011, 05:47 PM
:goodjob: MapScriptTools 1.02 :hatsoff:
This version should fix the MAC issues - I hope. I've also had a look and tried to fix those same issues within the map-scripts.
Mana-Types are now automatically recognized and reported in all FFH modmods.
In SmartMap I've rewritten the addGoodies() function to produce fewer of them. They are also not clumped anymore.
Reefs are now likely to expand into a chain. (Some balancing may still be needed here.)
It also comes with a new map: Planetfall_101_mst.py.

Temudjin
Jul 29, 2011, 06:03 PM
@HardRocker: I think RFC works only with it's very own .CivBeyondSwordWBSave scenario maps.

@Xyth: You inspired me.
I've had a closer look at reefs and expanded a bit on them, with somewhat longer chains though. The place to look at is the FeaturePlacer class: there are two functions - placeReefs() and expandReef() - which handle reefs.
I haven't play-tested them much - RifE seems to be the only mod that handles them yet - so there may be some issues.

Xyth
Jul 29, 2011, 07:20 PM
Thanks for the update Temudjin!

Just did a quick test of each mapscript (default settings) and everything seems to be working great on Mac except the Smartmap and Planetfall scripts. The latter isn't a problem given Planetfall itself doesn't work on Mac. Smartmap never worked on Mac either though it's probably fixable. The errors thrown are:

Traceback (most recent call last):

File "SmartMap_922_mst", line 278, in addBonuses

File "SmartMap_922_mst", line 2717, in addBonuses2

NameError: global name 'sorted' is not defined
ERR: Python function addBonuses failed, module SmartMap_922_mst
Traceback (most recent call last):

File "SmartMap_922_mst", line 3380, in assignStartingPlots

NameError: global name 'sorted' is not defined
ERR: Python function assignStartingPlots failed, module SmartMap_922_mst

I'm guessing sorted() is another 2.4 feature. Not a problem though, I'm more than happy with everything else included. Thanks too for the expanded reefs, I'll let you know how I get on with them :)

EmperorFool
Jul 29, 2011, 07:36 PM
Can you please post the code for those broken lines with a few lines on either side for context? It's probably a simple matter cloning the list and sorting it, but I don't know without the code.

Xyth
Jul 29, 2011, 08:03 PM
Can you please post the code for those broken lines with a few lines on either side for context? It's probably a simple matter cloning the list and sorting it, but I don't know without the code.

Sure thing, here they are:

bonusIdsAndOrder = []
for bonusId in range(cgc.getNumBonusInfos()):
bonusInfoXML = cgc.getBonusInfo(bonusId)
if bonusInfoXML.getPlacementOrder() >= 0:
bonusIdsAndOrder.append((bonusId,bonusInfoXML.getP lacementOrder()))

bonusIdsAndOrder = sorted(bonusIdsAndOrder, key=operator.itemgetter(1))
# mst.printList( bonusIdsAndOrder, "bonusIdsAndOrder:", rows = 1, prefix = "[SMap] " )

#pair continent lists with their scores, and sort by the scores
listsScoresPlayers = []
for index in range(len(postContinentLists)):
listsScoresPlayers.append((postContinentLists[index], postContinentScores[index], 0))

listsScoresPlayers = sorted(listsScoresPlayers, key=operator.itemgetter(1))
listsScoresPlayers.reverse()
mst.printList( listsScoresPlayers, "listsScoresPlayers:", rows=1, prefix = "[SMap] " )

Temudjin
Jul 30, 2011, 04:56 AM
I think I have the fix, could you check the file? Thanks for pointing this out.

What seems to be the problem with Planetfall_101_mst ? The whole point of including it is that the map should work with any mod ?

Xyth
Jul 30, 2011, 10:26 PM
I think I have the fix, could you check the file? Thanks for pointing this out.

Seems to work perfectly now, thank you.

What seems to be the problem with Planetfall_101_mst ? The whole point of including it is that It should work with any mod ?

This also seems to be working without issue now, I'm not sure why it wasn't the first time I tried it. Was probably something unrelated that I was tinkering with at the time.

The new reef functionality is great, I'm still experimenting to find the ideal numbers but I've seen some very fun looking maps generated with it. Thanks so much for this.

I have a couple suggestions for a future version that I was able to implement myself (roughly) but I imagine could be useful to others. Firstly, it seems that some terrain graphics set (Blue Marble in this instance) don't look right when ocean tiles are directly next to certain land tiles. I added a boolean parameter to expandifyCoast() to enable/disable the deep water near cliffs functionality.

However, I've noticed that even with this switched off there is still the occasional instance of land and ocean tiles blending. It doesn't seem to happen when the coast isn't expanded and I switched off bulkifyIslands() to make sure it wasn't that (it only seems to occur on islands). I've been testing this on Firaxis' Archipelago and Pangaea maps. Is there some method of preventing this completely or checking for the existence of ocean next to land and converting it to coast?

Secondly, I 'converted' (quotes to indicate that I wouldn't trust it to work well beyond HR) the MarshMaker class to work with FEATURE_SWAMP if TERRAIN_MARSH isn't found. This might be something useful to others too and I'm sure you could code it far better than I.

Temudjin
Jul 31, 2011, 06:35 AM
That's good news :). Thanks

Cliffs: Wasn't aware of that, but I'm not very graphical minded. Ok, I will put an extra parameter 'bCliffs' into expandifyCoast().
bulkifyIslands() deals with plots and not with terrain, so it shouldn't matter as long as it's called before the terrain is generated. mst.mapPrettifier.bulkifyIslands() should be called somewhere at the start of generateTerrainTypes().
A first parsing of my special regions code (which changes plots after terrain is generated) brought no results either (yet).
To kill that problem you could put

for inx in range( map.numPlots ):
x,y = mst.coordByIndex(inx)
if mst.isCoastalWater(x,y):
map.plot(x,y).setTerrainType( mst.etCoast, False, False )


somewhere late into normalizeAddExtras(). I would certainly like to know where that problem comes from though.

Swamps: Actually I thought that feature swamp (or feature marsh) was the old solution and modern mods use terrain marsh instead. In Civ5 it's feature marsh though, so I might as well reconsider my approach. Which mods do use feature swamp?

Xyth
Aug 01, 2011, 02:03 AM
I would certainly like to know where that problem comes from though.

It seems to occur only on islands, so far anyway, for example offshore islands on a Pangaea map or in Archipelagos. This is what lead me to suspect bulkifyIslands() but it definitely still occurs with that disabled. It doesn't occur in connection with BigBogs or BigDents. It's a mystery, though fortunately rare. I'll let you know if I gain any more insight into it.

Thanks for that fix too, I won't apply it yet in case I can help figure out the cause.

Swamps: Actually I thought that feature swamp (or feature marsh) was the old solution and modern mods use terrain marsh instead. In Civ5 it's feature marsh though, so I might as well reconsider my approach. Which mods do use feature swamp?

I think Realism Invictus does, I'm using their graphic for the next version of HR. I'm not sure what other mods use a Swamp/Marsh feature. I think most go for the terrain version as it's readily available from Colonization. I didn't like the way it looked though and having it as a feature gives me a few more options in the XML.

lemonjelly
Aug 01, 2011, 06:22 AM
Is there any possibility for you to make Archipelago, Big And Small, ErebusContinent, WorldOfErebus work with this?

Temudjin
Aug 01, 2011, 12:59 PM
Well for 1.01 I added PerfectMongoose_3101_mst and for 1.02 Planetfall_101_mst. I guess I'll try to continue the tradition to bring another script into the family with the next release, which I'm working on, but which will (also traditionally) take a while.
So to answer your specific question the chances are good for one of them. :mischief:

lemonjelly
Aug 02, 2011, 07:02 AM
And is there an easy way to add compatibility for the others? ;)

Temudjin
Aug 06, 2011, 03:49 AM
Yes. :king:
Actually that's fairly easy. For the overwhelming majority of map-scripts it should be enough to follow the steps, which are shown in the 'How To Guide' of my 2nd post.
Basically you have to copy a template - that you can find at the very end of MapScriptTools.py - into the map-script and go through the template line by line, follow the comments and either adjust corresponding original function-names and call them, or just comment out the original.
It shouldn't take more than an hour or so to establish basic compatibility unless you want to add more user-options, which may take a bit longer. You might want to take a look into Ringworld3 at the 'Custom Map Option Interface' code and use that as another template.

And
Nov 12, 2011, 03:51 AM
Good morning once more,
I've downloaded latest MapScriptTools but I have a weird problem: SmartMap_922_mst doesn't appear in my map list. The file is there but I can't see it into the game. Any hints?
Thank you.