[Map Script] PerfectWorld.py

Version 1.01 is posted!

Ok, I added some global tuning variables at the beginning of the file for easier customization. Be careful though, the slightest changes can have drastic climate altering, seismic results!

Changing the rainfall levels for different terrain types from hard coded values to percentages changed the character of the maps generated quite a bit, but I think most of you will prefer this way of doing it. Interestingly, the larger the continents get the more the deserts begin to break up and become scattered across plains. Since large continents tend to get less rain across the middle, and deserts are now limited by a percentage of the map, they are naturally spread more thinly. On pangea type worlds that happen occasionally this can look very strange.

I also slightly changed the dimensions of the 'large' size map so that the heightmap is generated on a finer grain. This prevents it from generating so many pangeas.

Give it a shot!
 
occasionally I get some maps that end up with virtually no desert (less than 5% of land tiles) and instead endless plains (with no trees). Any idea what causes this and what values I can adjust to reduce this?

I, like you, enjoy "seas" of deserts on larger landmasses, but this script will 2 out of 5 maps create this plains version instead of the typical map.
 
occasionally I get some maps that end up with virtually no desert (less than 5% of land tiles) and instead endless plains (with no trees). Any idea what causes this and what values I can adjust to reduce this?

I, like you, enjoy "seas" of deserts on larger landmasses, but this script will 2 out of 5 maps create this plains version instead of the typical map.

This kind of thing can happen when there is a landmass that is very large. The problem is that the rain has to come from the ocean, carried by winds. When there are large areas of next to no rain, the percent finder for desert and plains has to come up with a threshold that in this case might not be accurate enough due to the very small amounts involved. I used to get this alot on 'large' size maps, so I changed the size slightly so that it tends to generate smaller continents.

I still need to do some testing, but I suspect that I might be using a float somewhere where I need a double. I'm not exactly sure what causes this, but I noticed it happens on some map sizes more than others.

As for a suggestion, you might try lowering the LandPercent variable and play on the next larger size map. Changing the DesertPercent might just give you all desert instead of all plains.

Edit: Ok, I figured it out. How this works is, the rain map is normalized to be between 0.0 and 1.0. The problem is, rainfall at the ocean is set to 0.0. That means that the lowest rainfall on land might be well above 0.0, and closer to the desert threshold and thus having a high likelyhood of being plains. The model assumes that 0.0 will be the least rainfall which is not always the case. I'll have a fix shortly.
 
Edit: Ok, I figured it out. How this works is, the rain map is normalized to be between 0.0 and 1.0. The problem is, rainfall at the ocean is set to 0.0. That means that the lowest rainfall on land might be well above 0.0, and closer to the desert threshold and thus having a high likelyhood of being plains. The model assumes that 0.0 will be the least rainfall which is not always the case. I'll have a fix shortly.

Yay, a new version to play with :)

As for the deserts, with your original version all I did to 'fix' them was work with the highest rainfall since I remembered seeing where you reset all of the ocean rainfall to zero. Here's the code from the previous version with my quick hack in it (in GenerateTerrainMap()):
Code:
        #initialize terrainMap with OCEAN
        for i in range(0,hm.mapHeight*hm.mapWidth):
            self.terrainMap.append(self.OCEAN)
            if highestRainfallMM < rm.rainMap[i]:
                highestRainfallMM = rm.rainMap[i]

        highestRainfallMM *= 12000 #highest average rainfall possible in mm
The result is that I still get some good sized desert areas on 'normal' maps with multiple continents but it's a bit more forgiving on maps with large continents. The hack is a bit over-simplified though and one area with high rainfall will effectively increase the likelyhood of deserts on the rest of the map.

I'll have to grab the update and play around with it after work, hopefully I can just drop my climate based terrain changes right in. ;)

I've had some incredible games with these maps, the terrain is absolutely fabulous. Unlike typical random maps the climate makes sense and adds a whole new layer of strategy to the game, especially if you find yourself blocked off by large mountain ranges or unihabitable spans of desert. AI expansion has also been generally slower in my games and for once it makes sense when they settle a bit away from their existing cities. I guess I would say the maps are earth-like in the way grass/plains/deserts/mountains/hills are distributed but still random enough in shape to keep them interesting between different games.
 
Ok, 1.02 is published!

Wow, what a difference now that I don't have to explain away the fact that the map was all plains! I can say with confidence that the settings you choose for deserts etc. will give the expected results now.

Next on the agenda are those lakes. For one thing, any time you see a one square lake it's a bug. I tried to eliminate those, but I did it in a somewhat clumsy manner. I'm going to make the size of lakes proportional to the total river lengths flowing into them. Right now I'm seeing alot of instances where you have the Nile, and the Amazon, AND the Mississipi flowing into the same 3 square lake. I'm not comfortable with that.
 
seven05, there are some changes that will affect what you were doing. Check out the FindValueFromPercent function. What it does is return a threshold such that the given percentage of the total map will be above or below the return value. This allows for easy tuning of anything that you want to set as percentages. If you need a calculation more complex than greater or less than, then you can prepare a map of pre-calculated values. This is how I tuned peaks and hills.

Anything that depends on rainfall is a good choice for this method, since rainfall can vary widely from map to map, and this can provide consistency.

Temperature related stuff is still absolute, since temperature is so heavily dependant on lattitude and maintains it's own form of constistency.
 
seven05, there are some changes that will affect what you were doing. Check out the FindValueFromPercent function. What it does is return a threshold such that the given percentage of the total map will be above or below the return value. This allows for easy tuning of anything that you want to set as percentages. If you need a calculation more complex than greater or less than, then you can prepare a map of pre-calculated values. This is how I tuned peaks and hills.

Cool, thanks for the heads up. I won't have time to mess with it until this weekend though. And you tuned the peaks and hills? I'll have to see what that gives me now :)

For your lakes & rivers, one thing I did was change way you remove lakes. Originally, all you did was change the plot from 'ocean' to 'land' without altering the heightmap. Since the flowmap was based on the heightmap it appeared to creat a LOT of lakes, especially in the larger continents where a big lake or several lakes had been cleaned up. Since the temp/rain map would cause those same areas to be deserts I thought it was a bit odd having a large desert full of lakes. Anyway, all I did was go into the lake cleanup code and add a line to set the heightmap for each plot to sealevel where it changed the plot type to land (I think I had to change the main code to cleanup lakes before generating the flowmap too but I don't recall). That appeared to have an impact on the number of rivers and small lakes. Since it was still appearing to almost prefer deserts for river placement (making them some of the most fertile areas, which I thought was a bit odd) I also made a slight adjustment to the river generation code to make it unlikely to even try to create a river if the plot rainfall was below the desert threshold. A typical map for me now has very few, if any, lakes in deserts and only a couple of desert rivers. Unfortunately there are also very few rivers altogether since most of them were in the deserts.
 
I think one of the reasons that rivers often turned up in deserts was because deserts tend to happen on the widest parts of continents where there might be little rain per square, but lot's of squares to contribute to the watershed. Since there is no evaporation figured in, the water just keeps running.

It didn't bother me too much because it definately does make those areas more useful, and the first version of the map had soooo much desert. I'm going to try to do something more sensible with the lakes and rivers. However, if you google maps the Nevada desert near Reno, you'll see alot of similar lakes that act as evaporation pans. :)
 
Well, that was easy :)

I just used the global ForestTemp & JungleTemp to add in the 'climate based terrain' in about 60 seconds. So far it's working well, I just need to play around with the global values for personal preferences. Any plans to put in in-game options to control those values?

Also, I'm not sure if you're aware of this, the mapscript isn't entirely MP compatible. When you use it the players will all be out of sync and upon reconnecting their civs will be in a different starting plot. The workaround is to start with appropriate AI players and have the other players join once the map has been created and take over the AI civs.
 
Well, that was easy :)

I just used the global ForestTemp & JungleTemp to add in the 'climate based terrain' in about 60 seconds. So far it's working well, I just need to play around with the global values for personal preferences. Any plans to put in in-game options to control those values?

Also, I'm not sure if you're aware of this, the mapscript isn't entirely MP compatible. When you use it the players will all be out of sync and upon reconnecting their civs will be in a different starting plot. The workaround is to start with appropriate AI players and have the other players join once the map has been created and take over the AI civs.

I'm not sure yet what values people will really want to change from game to game. I put them in so that people can adjust things to their ideal of a perfect world.

I have no clue what the requirements are for MP. Do you know of a script that handles this well that I can study? What's the issue? Do players choose their starting locations? I've never even played MP.

Right now I'm trying to improve lake generation, and in the process I found an occasional bug in my area generator that I use for starting placement and lake filling. It is going to be a nightmare to track this down because it works fine for most maps. I need to impliment a way to save maps in Python so I can debug with the same test map, otherwise there's no way to know if I fixed it or if it's just a different map.
 
I'm not sure yet what values people will really want to change from game to game. I put them in so that people can adjust things to their ideal of a perfect world.
Sea level, climate (rainfall & temps) and peak/hill percentage would be some good basic options.

I have no clue what the requirements are for MP. Do you know of a script that handles this well that I can study? What's the issue? Do players choose their starting locations? I've never even played MP.
I'm not 100% certain what causes it to go out-of-sync. It may be the long initialization time or the use of 'random' rather than the mp-safe 'dice' function. Players don't chose their starting location, but if they're in the game when you generate the map they'll see themselves in one place and after re-connecting to get back in sync they'll be somewhere else entirely. This leads me to believe it's a problem somewhere in the starting plot function. Most of the other map scripts I've tried worked without a problem, one I know works fine in MP is Nercury's 'Planet generator' which you can grab from the forum here.
 
I need to impliment a way to save maps in Python so I can debug with the same test map, otherwise there's no way to know if I fixed it or if it's just a different map.
Why don't you just set the seed of the random number generator?
 
Why don't you just set the seed of the random number generator?

I'll try that first. Hopefully, I was consistent in which random generator I used :crazyeye: .

I have to do most of my work in a place where I don't have access to civ, so I probably used random() until the end of the process.
 
I'm not 100% certain what causes it to go out-of-sync. It may be the long initialization time or the use of 'random' rather than the mp-safe 'dice' function. Players don't chose their starting location, but if they're in the game when you generate the map they'll see themselves in one place and after re-connecting to get back in sync they'll be somewhere else entirely. This leads me to believe it's a problem somewhere in the starting plot function. Most of the other map scripts I've tried worked without a problem, one I know works fine in MP is Nercury's 'Planet generator' which you can grab from the forum here.

I found this in the CvMapScriptInterface file:
CvMapScriptInterface said:
* normalizeStartingPlotLocations() # This function only matters if any teams of more than one civ (aka permanent alliances) exist at game launch. This function works to group team members together as best it can. If you hardwire any start plots for specific players and don't want the game to mess with them, shuffing them around, then you need to override (disable) this function.

Could this be what is happening? Once I start the assignStartingPlots, I only use the dice for randoms.

Also, my findStartingPlot function is completely dependant on my assignStartingPlots, so if it's called separately it won't work the same way. Ew, I would hope they would not do that but they might.
 
I have noticed sometimes with lake generation in deserts, an oasis will be inside the lake. This has only happened once and I was fooling around in the world builder so I cannot be 100% certain I didn't place it accidentally. I know this is vague but I will keep my eyes open for it if I see it again.
 
I have noticed sometimes with lake generation in deserts, an oasis will be inside the lake. This has only happened once and I was fooling around in the world builder so I cannot be 100% certain I didn't place it accidentally. I know this is vague but I will keep my eyes open for it if I see it again.

Yeah, that will be fixed in the next version. The problem is that I'm using my own terrain tracking to decide where to place them but I didn't update my terrain when I made the lake, so my feature generater thinks the lake is still desert.
 
Could this be what is happening? Once I start the assignStartingPlots, I only use the dice for randoms.

Also, my findStartingPlot function is completely dependant on my assignStartingPlots, so if it's called separately it won't work the same way. Ew, I would hope they would not do that but they might.
We don't run team games so if by 'This function only matters if any teams of more than one civ (aka permanent alliances) exist at game launch' they mean the normalize functions only runs if you have teams then that definately isn't the problem.
 
I've played a team game using this map script. We got an Oout of sync on game launch, but when he reconnected, he was in the same spot.
 
We don't run team games so if by 'This function only matters if any teams of more than one civ (aka permanent alliances) exist at game launch' they mean the normalize functions only runs if you have teams then that definately isn't the problem.

Yuck, I'll have to tackle this for 1.04. Nercury's map uses the default implimentation BTW, which would be fine except I need to screen out the new world. As far as I can see though, I'm using a very similar routine that is in the DLL. I can't imagine why a new starting location would be calculated on reconnect.

Seven05, do you have your civ set up to make a Python debug log? There are some print statements in the findStartingPlot function that might indicate whether it's being recalled after the initial placement. If it's re-calling the default procedure in the DLL though, nothing would show up.
 
What do you guys think of floodplains? Right now I have them only in the desert and if there is a river there is always a floodplain. Maybe that's fine.
 
Top Bottom