View Full Version : [Map Script] PerfectWorld.py


Pages : [1] 2 3

cephalo
Aug 23, 2007, 04:54 PM
Hi Folks!

This map script for vanilla Civ4,Warlords, BtS and most mods based on Civ4 generates a random, earth-like map, usually with a 'New World' with no starting locations that can only be reached with ocean going technology. Landforms are created using a random heightfield and a plate tectonic scheme. Climate is simulated using the interaction between the landforms and geostrophic winds. Though great pains are taken to semi-accurately simulate landforms and climate, the goal must be to make unpredictible, beautiful looking maps that are fun to play on.

Download the file here from the downloads database. (http://forums.civfanatics.com/downloads.php?do=file&id=8042)

To use this map, put it in your Civilization 4\PublicMaps folder, not in your My Documents\My Games\Civilization 4\PublicMaps folder.

-- Map Options --
New World Rules:
Start in Old World(Default): Reserves some continents to act as a new world
Start Anywhere: Disables the new world functionality

Pangaea Rules:
Break Pangaeas(Default): Breaks up Pangaeas with a simulated meteor shower (really big meteors)
Allow Pangaeas: Allow pangaeas to exist. Keep in mind that this will likely eliminate any 'New World' as well.

-- Summary of creation process: --
First, a random heightfield is created using midpoint displacement. The resulting altitudes are then modified by a plate tectonics scheme that grows random plates and raises the altitudes near the plate borders to create mountain ranges and island chains.

In generating the plot types from a heightmap, I had found that using peaks for high altitude and land for less altitude created large clusters of peaks, surrounded by a donut of hills, surrounded again by a donut of land. This looked absolutely terrible for Civ, so I made it such that peaks and hills are determined by altitude *differences* rather than by absolute altitude. This approach looks much better and more natural.

The terrain generator gives the other needed visual cues to communicate altitude. Since air temperature gets colder with altitude, the peaks will be plots of ice and tundra, even near the equator, if the altitude is high enough. Prevailing winds, temperature and rainfall are all simulated in the terrain generator. You will notice that the deserts and rainforests are where they should be, as well as rain shadows behind mountain ranges.

Rivers and lakes are also generated from the heightmap and follow accurate drainage paths, although with such a small heightmap some randomness needs to be thrown in to prevent rivers from being merely straight lines.

Map bonuses are placed following the XML Rules but slightly differently than the default implimentation to better accomodate this map script.

I've always felt that the most satisfying civ games are the ones that provide a use for those explorers and caravels. Though the map generator does not explicitly create a 'New World', it will take advantage of any continents that can serve that purpose. No starting locations will be placed on these continents. Therefore, the likelyhood of a significant new world is very high, but not guaranteed. It might also come in the form of multiple smaller 'New Worlds' rather than a large continent.

Enjoy!

Here are some screenshots to illustrate some of the features of PerfectWorld.

Here is a typical example of a standard sized map overview.
http://forums.civfanatics.com/attachment.php?attachmentid=170608&stc=1&d=1204769766

From the same map as above, here is a valley near the equator. Notice how the terrain and features subtly communicate altitude. The hot jungle lowlands are kindof snaking through some higher, and slightly colder, altitudes.
http://forums.civfanatics.com/attachment.php?attachmentid=170607&stc=1&d=1204769766

From the same map again, here is a nice coastline. This continent is part of the 'New World' so no starting places were put here.
http://forums.civfanatics.com/attachment.php?attachmentid=170606&stc=1&d=1204769766

Here is an overview of a huge sized map. It looks like this world found itself on the wrong side of some very large meteors in the distant past. Meteors are used to break up pangaeas which naturally interfere with the new world functionality, but if you happen to like pangaeas, you can turn this option off with the many tuning variables at the beginning of the script.
http://forums.civfanatics.com/attachment.php?attachmentid=170610&stc=1&d=1204769766

From the huge map now, another example of altitude affecting the terrain. This northern peninsula has a ridge of tundra which, along with the direction of the rivers, helps create an illusion of altitude.
http://forums.civfanatics.com/attachment.php?attachmentid=170611&stc=1&d=1204769766

Here is an example on the huge map how resources are placed. I captured a junction of three continents to show that, to encourage trading, different continents have different resource sets. One continent has wheat and pigs, another cows and corn, and the other sheep and rice. These resources are designed in the XML to avoid appearing on the same continent, and this rule is respected when starting plots are normalized also.
http://forums.civfanatics.com/attachment.php?attachmentid=170609&stc=1&d=1204769766

Version History
1.13 - Fixed a bug where starting on a goody hut would crash the game. Prevented start plots from being on mountain peaks. Changed an internal distance calculation from a straight line to a path distance, improving start locations somewhat. Created a new tuning variable called DesertLowTemp. Since deserts in civ are intended to be hot deserts, this variable will prevent deserts from appearing near the poles where the desert texture clashes horribly with the tundra texture.

1.12 - Found a small bug in the bonus placer that gave bonuses a minimum of zero, this is why duel size maps were having so much trouble.

1.11 - limited the features mixing with bonuses to forests only. This eliminates certain undesireable effects like floodplains being erased by or coinciding with oil or incense, or corn appearing in jungle.

1.10 - Wrapped all map constants into a class to avoid all those variables being loaded up when PW is not used. Also this makes it a little easier to change them programatically. Added two in-game options, New World Rules and Pangaea Rules. Added a tuning variable that allows bonuses with a tech requirement to co-exist with features, so that the absence of those features does not give away their location.

1.09 - Fixed a starting placement bug introduced in 1.07. Added a tuning variable to turn off 'New world' placement.

1.08 - Removed the hemispheres logic and replaced it with a simulated meteor shower to break up pangeas. Added a tuning variable to allow pangeas.

1.07 - Placing lakes and harbors after river placement was not updating river crossings. Resetting rivers after lake placement should solve this. Fixed a small discrepancy between Python randint and mapRand to make them behave the same way. Bonuses of the same bonus class, when forced to appear on the same continent, were sometimes crowding each other off the map. This was especially problematic on the smaller maps. I added some additional, less restrictive, passes to ensure that every resource has at least one placement unless the random factors decide that none should be placed. Starting plot normalization now will place food if a different bonus can not be used due to lack of food. Changed heightmap generation to more likely create a new world.

1.06 - Overhauled starting positions and resource placement to better suit the peculiarities of PerfectWorld

1.05 - Fixed the Mac bug and the multi-player bug.

1.04a - I had unfairly slandered getMapRand in my comments. I had stated
that the period was shortened unnecessarily, which is not the case.

1.04 - Added an option to use the superior Python random number generator or the getMapRand that civ uses. Made the number of rivers generated tunable. Fixed a bug that prevented floodplains on river corners. Made floodplains in desert tunable.

1.03a - very minor change in hope of finding the source of a multi-player glitch.

1.03 - Improved lake generation. Added tuning variables to control some new features. Fixed some minor bugs involving the Areamap filler and fixed the issue with oasis appearing on lakes. Maps will now report the random seed value that was used to create them in the PythonDbg file, so they can be easily re-created for debugging purposes.

1.02 - Fixed a bug in the way desert placement was calculated. This also required a readjustment of the default values.

1.01 - Added some global tuning variables for easier customization. Fixed some minor bugs that caused deserts to get out of control sometimes.

Sine Nomen
Aug 23, 2007, 05:19 PM
This is fantastic, especially the way climates are generated. I got so tired of playing on maps with jungle and desert splattered randomly across the same latitudes that I pretty much stopped playing except for on maps that I've created. :) The only place where I think it needs work is the shape of the continents - they're a bit web-like and all seem to snake together. Also, having Sahara-like deserts that don't fade into grassland after three tiles is wonderful, but some of these deserts might be a little *too* big. If the way they're generated is based on the shape of the continent (this is great!), having some different options for continent generation might be helpful. Nercury's Planet Generator script does a good job of creating realistically-formed continents - if you could incorporate that with your wonderful climate generator code the script would be, well, perfect. Good work!

cephalo
Aug 23, 2007, 07:52 PM
Yeah, 'perfect' is quite a boast. I called it 'PerfectWorld' because I wanted to make a map that was my ideal for a good Civ game. It's not really perfect just yet.

About those large deserts; I had also thought that there might be a little too much desert with the current setup. However, the real world is mostly plains and desert. Rainforests and lush farmlands are actually somewhat rare. In game terms, having an abundance of the drier climates makes the grasslands alot more valueable for food production, while the dry interors will naturally have many of the important mineral resources. After some playtesting I decided to keep it.

Also, bringing in more rain is tricky lol. The only things that are controlled by lattitude are the prevailing winds and initial temperature. Tweaking certain variables by a few tenths of a percent makes the world a gigantic jungle. :blush: I tweaked and tweaked until most of the maps were balanced lol. If, for example, all the continents end up in the rain zones at the equator and +/- 60 degrees, then even now the world is mostly rainforest. It's a big 'what if' scenario.

LDiCesare
Aug 24, 2007, 09:21 AM
I must try it! Great to see someone else tried a generator like this. A pity your thumbnails are so small, I can't visualize the results until I've tried it myself.

cephalo
Aug 24, 2007, 10:23 AM
I would suggest that before anyone commits to a game, generate a few maps and use the console command 'game.toggledebugmode' to make sure it's to your liking. Perhaps I can put together a better screenshot when I get home.

TheLastOne36
Aug 24, 2007, 04:08 PM
is this only for vanilla?

cephalo
Aug 24, 2007, 08:22 PM
is this only for vanilla?

I do not own the expansions yet, so I'm not actually sure what additional requirements they have regarding map scripts. It may work fine for all I know.

cephalo
Aug 24, 2007, 08:36 PM
Here are some more detailed screen shots of a typical map result. The one on the left is the main 'Old World' area where people start.

The middle one is an overview of the 'New World' continents with no starting areas.

The picture on the right is a close up example of a valley in the northern rainy lattitudes. The icy and tundra area to the north west is what high altitude looks like. It takes a little imagination to see it that way, but it looks fairly natural, especially since rivers tend to lead away from these areas.

LDiCesare
Aug 26, 2007, 10:57 AM
This script works fine with the expansions. I didn't check if the feature generator makes it compatible with all mods, but it's perfectly usable with regular BtS.
I'll make a few comments if I may:
I think the deserts tend to get overboard quite easily. Very often I see huge deserts and almost no usable land in the most part of a continent, despite one or two lakes in the middle of the continent, which only generate a single plain nearby. It's very hard to tune unfortunately.
The rivers generated are gorgeous. Very nice work. I'm probably going to rewrite my own rivers along the same lines if I can find the time.
I also think there are too few hills with regards the number of peaks generated.
Nice job overall. :goodjob:

cephalo
Aug 27, 2007, 09:30 AM
A word of warning in regards to river generation. Even though the generateTerrain overridable function wants a list of terrains with (0,0) in the NW corner, the plots in CvMap are arranged with (0,0) in the SW corner! Jeez, it took me days to figure out why my rivers were running backwards. With this being a random map generator, I was oblivious to the fact that I was looking at my maps upside down. :lol:

Seven05
Aug 28, 2007, 08:26 PM
The maps generated with this script are very nice, especially the terrain distribution which itself is fantastic.

My only complaint so far is that the use of tundra & ice to simulate high altitude frequently has some 'unpleasant' results like a single tile of ice between peaks and jungles.

If you're accepting any 'wish lists' it would be very nice to have more control in the game. In particular the ability to control continents touching the poles, tundra/ice simulating high altitude and overall temperature & 'roughness' of the world. Nercury's planet generator has excellent controls and great results for landmasses.

Anyway, great work! :)

cephalo
Sep 01, 2007, 07:11 PM
Ok, so I'm on vacation visiting family and showing my brother in law my map script. The first thing out of his mouth is, "Wow, look at all that desert." When I get back I'll make a fully tunable version.

I also have to do something about those starting areas. It's basically the default with no new world placement, and that really only works with roundish continents. Sometimes you can be placed on a snaky peninsula that goes through the arctic, and the game thinks you're on the best continent so it's ok. I'll have to work on it some more.

Seven05
Sep 02, 2007, 10:33 AM
I have done some tweaking that I'd be happy to share with you, mainly with the player starting positions and removing the tundra/ice simulating altitude. To 'fix' the player starts what I did is re-write the entire section to that it first checks to see if the map has a single huge landmass, if it does that becomes the old world and everything else is the new world. If it's not a single huge landmass it makes the largest landmass the new world, the second largest the old world and then continues to add to the old world until the total old world size is 60% of the total land. What happens most often with that change is the players start out in smaller clusters on different continents, normally 2-4 civs per landmass (except on the pangea-like worlds). I was going to add a latitude check to add some weight to staring closer to the equator but I don't think it really needs anything else from what I've seen in my countless test builds.

Anyway, if you'd like I can post the code for that to save you some trouble.

As for customization options it would be nice to have some control over the frequency of rivers (especially in deserts), overall temperature, overall rainfall and the 'roughness' of maps.

Asthetically, the only thing that could be improved is the long straight mountain ranges as they can look pretty bad when you end up with a straight line of 10+ peaks. Creating some channels in the snakey continents to break them up into multiple continents would be a nice feature too but not really critical.

Seven05
Sep 03, 2007, 12:34 AM
So I've been playing around with this a bit to tweak it more to my liking and figured I should at least share the code in case you find it helpful.

The first is my re-write of getNewWorldID(), it should be pretty self-explanatory:
def getNewWorldID(self):
nID = 0
continentList = list()
for a in self.areaList:
if a.water == False:
continentList.append(a)

totalLand = 0
for c in continentList:
totalLand += c.size

print totalLand

#sort all the continents by size, largest first
continentList.sort(key=operator.attrgetter('size') ,reverse=True)
print ''
print "All continents"
print self.PrintList(continentList)

#First, make sure we don't have a single huge landmass, if we
#do, that will be the old world
oldWorldSize = 0

if float(continentList[0].size)/float(totalLand) > 0.50:
oldWorldSize += continentList[0].size
del continentList[0]
else:
#second largest continent is 'Old World' giving us a larger 'new world'
#to explore and forcing the game to split player starts up into smaller
#groups on the remaining landmasses if possible
oldWorldSize += continentList[1].size
del continentList[1]

#if the remaining continents are large enough we can continue
#if not we can just call everything else 'new world'
if float(oldWorldSize)/float(totalLand) < 0.50:
biggestNewWorld = continentList[0]
del continentList[0]

for n in range(len(continentList)):
oldWorldSize += continentList[0].size
del continentList[0]
if float(oldWorldSize)/float(totalLand) > 0.60:
break

#add back the biggestNewWorld continent
continentList.append(biggestNewWorld)

#get ID for the next continent, we will use this ID for 'New World'
#designation
nID = continentList[0].ID
del continentList[0] #delete to avoid unnecessary overwrite

#now change all the remaining continents to also have nID as their ID
for i in range(self.mapHeight*self.mapWidth):
for c in continentList:
if c.ID == self.areaMap[i]:
self.areaMap[i] = nID

return nID


The next is some 'noise' generation. This is kind of dirty but it does the trick and would be easy to impliment as an optional process. I simply added two passes to the end of GenerateHeightField(). The intention was to break up the landmasses a little more, particularly near the poles. It needs some work though as it ends up adding a lot of peaks on most maps. I did it here, before all of your other processing to help conceal the 'noise' effect a little better. Since this takes place before PerformTectonics() you still get the really good landmass shapes and natural looking terrain distribution. In fact, it tends to create some very nice island chains on larger maps.
#Now a quick 'noise' pass that is biased to add more land near the equator and
#subtract more away from the equator
for y in range(0,self.mapHeight,1):
addBias = 1 - (abs((self.mapHeight * 0.5) - y) / (self.mapHeight * 0.5))
subBias = abs((self.mapHeight * 0.5) - y) / (self.mapHeight * 0.5)
for x in range(0,self.mapWidth,1):
i = self.GetIndex(x,y)
rand = random()
if rand < 0.2:
self.map[i] += random() * addBias * 0.5
elif rand > 0.7:
self.map[i] -= random() * subBias
#Finally a smoothing pass. The effect is stronger and more frequent near
#the equator.
for y in range(0,self.mapHeight,1):
bias = 1 - (abs((self.mapHeight * 0.5) - y) / (self.mapHeight * 0.5))
for x in range(0,self.mapWidth,1):
i = self.GetIndex(x,y)
avg = 0.0
if random() > bias:
for yy in range(y - 1,y + 2,1):
for xx in range(x - 1,x + 2,1):
ii = self.GetIndex(xx,yy)
avg += self.map[ii]
avg = avg/8
if avg < self.map[i]:
self.map[i] -= abs(avg - self.map[i]) * ((1.0 + bias) / 2)

Hope some of that helps. :)

cephalo
Sep 07, 2007, 07:30 AM
Well seven05, the first change you made basically changes the desired size of the old world from .60 to .50. You can accomplish the same thing probably by just changing that one hardcoded constant. Keep in mind that in this continent designation, coast is considered land, so when you generate a world with .25 landmass vs. water, you are almost always going to get a large continent bigger than .50.

The second change with the added noise just makes it noisier than the noise that comes with the heightfield generation. I can't remember all the places where I added noise to different aspects of the map generator, but the result has been continents of any size along with small islands dotting the seas here and there. That's noisy enough isn't it? Also, what's wrong with having land near the poles? In the real world after all, some of the largest continents come right up against the ice.

Next week I'm to change quite a few things and add alot of tunable variables like desert/plains/hills/peaks percentages and put them right at the beginning of the script as globals. So instead of saying "no rain = desert" I'm going to say 'no rain compared to the rest of the world = desert'. That way if the continents form mostly in the desert lattitudes they won't all be desert.

Rael
Sep 07, 2007, 12:48 PM
Well, first of all congratulations on your excellent map script. It's the best one I've ever used.
Secondly, I agree with Seven05 that there's too much land around the poles. CIV map is a rectangle which can't represent the Earth surface accurately. The equatorial zones end up shrinked and polar zones are stretched. To balance things out more ocean should be added around the poles to keep the tundra-rainforest ratio correct and create more earthlike maps (for example Rhye stretched the oceans near the poles to balance his Earth map).
I'm looking forward to the changes you want to make. I would also like to have an option to customize the number of continents and islands.

Rael

Seven05
Sep 07, 2007, 04:27 PM
Well seven05, the first change you made basically changes the desired size of the old world from .60 to .50.
Well, it's a little more than that :) You know your old method, the first check for 50% is simply to optimize the process since if it finds that than that continent is the old world and everything else is assumed to be the new world without stepping further into the process. The biggest change is in cases where you don't have one dominant landmass, in that case the largest is the new world and then the remaining continents are used to define the old world until the old world consists of at least 50% of the available land. On standard maps the difference between 50-60% is so small it doesn't matter, however on large and huge maps it makes quite a difference in player starting positions. From my experience (and with my noise changes) typical maps consist of two larger continents and anywhere from 1-3 smaller continents (continents being landmasses seperated by ocean). The next most frequent result is a single huge continent with some scattered islands and maybe a single additional small continent (room for 3-4 cities). Maybe one out of every ten maps gives me multiple continents of relatively equal size. Anyway, in all but the pangea style worlds the end result has the players more spread out over multiple continents whereas your original code preferred to put most of them on a single landmass.

The second change with the added noise just makes it noisier than the noise that comes with the heightfield generation. I can't remember all the places where I added noise to different aspects of the map generator, but the result has been continents of any size along with small islands dotting the seas here and there. That's noisy enough isn't it? Also, what's wrong with having land near the poles? In the real world after all, some of the largest continents come right up against the ice.
The noise (and smoothing pass) is biased by latitude so it's easy to tune the results. With my current settings the result is more subtractive noise near the poles which tends to break up large landmasses near the poles and replace them with scattered islands. The smoothing pass, being more prominent near the equator, has the effect of reducing the number of small islands away from the poles. So combined, it's not simply more noise, it's more noise near the poles and less noise near the equator. Adjusting the values used can create anything ranging from scattered islands everywhere to huge polar landmasses and equatorial islands. I chose to use noise to keep the landmasses interesting rather than simply applying a linear add/subtract pass.

It's not so much a matter of wanting NO land near the poles as much as it is a matter of preventing large landmasses near the poles. Having massive amounts of tundra/ice increases the chance of civs starting in those regions which can severely cripple them. While it's a fun start for a human player against AI opponents it makes for an exceptionally easy game if it's the AI that gets stuck there instead.

Next week I'm to change quite a few things and add alot of tunable variables like desert/plains/hills/peaks percentages and put them right at the beginning of the script as globals. So instead of saying "no rain = desert" I'm going to say 'no rain compared to the rest of the world = desert'. That way if the continents form mostly in the desert lattitudes they won't all be desert.
I'm looking forward to those changes :) I'll have to grab some in game screenshots showing some of the hidden potential of using your mapscript. In particular is the ability to apply different versions of grass, plains and deserts based on temperature which makes the maps look absolutely incredible.

cephalo
Sep 08, 2007, 02:09 PM
I'll have to grab some in game screenshots showing some of the hidden potential of using your mapscript. In particular is the ability to apply different versions of grass, plains and deserts based on temperature which makes the maps look absolutely incredible.

Wow, that sounds like fun.

Ok, I'm going to do this in two passes. First, I'm going to do the tunable stuff and publish it, since I can do it fairly quickly and easily. Then I'm going to work really hard on making those starting locations alot better.

The difficulty with placing starting locations is that much of the value depends on the starting locations of other civs, which are not necessarily known at the time of placement. You might think the guy with first pick has the best location, but that can be ruined by someone else being placed between him and the rest of his continent. A fine starting location can end up being a terrible one. You can fix that perhaps, but can you do it without ruining someone else's and ending up in an endless process?

I have some ideas on how to do this but it will be some work. I can create a value map with the values of each tile, then I can do some simultanious seed fills to find out what territory is likely to be claimed first and make adjustments in passes until everyone is within a certain value tolerance.

I really don't mind having a lot of unusable tiles on a map. I like large ice fields and large deserts and too much ocean. I think it adds a sense of adventure to the game. However, for that to work the starting areas have to take that into account so that one guy isn't getting the desert half of a good continent while his opponent gets all the grassland.

Seven05
Sep 09, 2007, 07:04 AM
I really don't mind having a lot of unusable tiles on a map. I like large ice fields and large deserts and too much ocean. I think it adds a sense of adventure to the game. However, for that to work the starting areas have to take that into account so that one guy isn't getting the desert half of a good continent while his opponent gets all the grassland.
That will definately be the tough part although in most cases the start positions haven't been too bad in my games. I've adjusted a lot of things though, both in your mapscript and with the mod that we use.

What is probably the best part of this map script is that the worlds created are 'tactically interesting.' The mountain ranges not only make sense and look good but they create natural obstacles rather than just being some randomly scattered peaks. The deserts are really good as well and create a good natural barrier to expansion, almost like oceans on land. It's really cool to see how the game evolves too, what was poor land early in the game can quickly become critical as resources are revealed.

Speaking of resources, if you write your own resource script make sure it's optional :) Right now this is working out very well of us with the combination of climate based terrain and resources restricted by terrain. For instance I have hot, temperate and cool plains so I can have a resource only appear on hot plains. Just like your script made the world look better by not banding terrain strictly by latitude this makes resource placement much more interesting.

Nercury
Sep 11, 2007, 07:42 PM
This map script caught my attention at once :). Nice job!

CIV map is a rectangle which can't represent the Earth surface accurately. The equatorial zones end up shrinked and polar zones are stretched. To balance things out more ocean should be added around the poles to keep the tundra-rainforest ratio correct and create more earthlike maps

I don't exactly know how landmasses are generated, but i guess it may be possible to randomly sink some land-heavy areas which are near poles to achieve that.

cephalo
Sep 11, 2007, 09:48 PM
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!

MrPopov
Sep 12, 2007, 09:04 PM
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.

cephalo
Sep 13, 2007, 07:52 AM
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.

Seven05
Sep 13, 2007, 11:18 AM
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()):
#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.

cephalo
Sep 13, 2007, 11:22 AM
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.

cephalo
Sep 13, 2007, 01:27 PM
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
Sep 13, 2007, 10:42 PM
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.

cephalo
Sep 13, 2007, 11:42 PM
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. :)

Seven05
Sep 14, 2007, 10:12 PM
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.

cephalo
Sep 15, 2007, 09:53 AM
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.

Seven05
Sep 15, 2007, 11:52 PM
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.

LDiCesare
Sep 17, 2007, 04:03 AM
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?

cephalo
Sep 17, 2007, 08:24 AM
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.

cephalo
Sep 17, 2007, 02:04 PM
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:

* 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.

MrPopov
Sep 17, 2007, 08:58 PM
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.

cephalo
Sep 18, 2007, 07:02 AM
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.

Seven05
Sep 18, 2007, 07:58 AM
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.

MrPopov
Sep 18, 2007, 09:05 AM
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.

cephalo
Sep 18, 2007, 09:09 AM
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.

cephalo
Sep 18, 2007, 09:24 AM
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.

Seven05
Sep 18, 2007, 04:28 PM
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.
I will enable the log and post some results for you next time we hook up for a game, probably Saturday.

As for the floodplains, I've had to modify it for myself (three types of desert in my mod). From a gameplay standpoint I think the only case outside of deserts that makes sense would be tundra since tundra is about as useless as desert unless you're lucky enough to have some trees. If you place them on plains/grassland they quickly overpower the normal food resources, or worse yet- they make cottage spam even more potent.

Anyway, I think as a 'pure' mapscript you should avoid any fundamental gameplay changes.

cephalo
Sep 19, 2007, 07:39 PM
1.03 is now published. The visible changes are somewhat small, but I had found many, many bugs that needed to be dealt with.

Lakes are now generated proportional to the river lengths flowing into them, and that proportion is tunable. There is also a tunable evaporation penalty for lakes created in the desert. Lakes that are one square in size are now legal, but no lake may exist such that removing one land square will connect it to the ocean, because any such lake will already be thus connected to form a harbor. So if you see such a lake, know that this map is behaving illegally.

Also, if you happen to be a modder with some Python saavy, each map will report in the PythonDbg file a seed value that is used to start the random number generator. So if you happen to find a map breaking the law, you can report them with this ID number.

Enjoy!

cephalo
Sep 19, 2007, 08:15 PM
Next up will definately be starting areas. One of the problems I see with having fair starting areas is, that I've noticed that in single player, AI civs are very good a getting into stone cold stalemates. Perhaps fair starting areas are really only desireable in multiplayer?

With the default implimentation, some civs get really, really bad starting areas that no amount of bonuses can fix. Also, sometimes people can start on their own fairly large continent and if it happens to be the player, then the game is way too easy. There's definately alot of room for improvement here.

seven05, how often have you seen that MP bug on my map? Do you think it could just be some one time glitch unrelated to the map? Before I work too hard, I had better get a handle on that.

Seven05
Sep 19, 2007, 08:36 PM
Very good results so far with the 1.03 fixes :)

We experienced the mp bug every time we tried to start a game with this mapscript, using another mapscript works fine as does starting the game and generating the map before the other players join.

cephalo
Sep 20, 2007, 07:05 AM
Very good results so far with the 1.03 fixes :)

We experienced the mp bug every time we tried to start a game with this mapscript, using another mapscript works fine as does starting the game and generating the map before the other players join.

First, I want to say thanks for all the helpful comments. I'm wondering if you have time on your next MP game, can you try to generate a map with the starting plot functions commented out? That will cause the default functions to be used and if it's stable then that tells me if I can concentrate wholly on my starting functions in finding the problem. assignStartingPlots and findStartingPlot are the only ones needing to be eliminated for this test.

cephalo
Sep 20, 2007, 12:45 PM
I've noticed something that might cause the MP problem. There is a function called CvPlayer.setStartingPlot and also one called CvPlot.setStartingPlot. My script only uses the CvPlayer version, maybe I need both? I'll try both, and after testing it tonight to make sure it won't crash the map I'll publish it. SmartMap uses both.

Seven05
Sep 20, 2007, 02:53 PM
First, I want to say thanks for all the helpful comments. I'm wondering if you have time on your next MP game, can you try to generate a map with the starting plot functions commented out? That will cause the default functions to be used and if it's stable then that tells me if I can concentrate wholly on my starting functions in finding the problem. assignStartingPlots and findStartingPlot are the only ones needing to be eliminated for this test.
No problem, thank you for the script! :)

I can do that quick check for you this weekend, if it does nothing I'll enable the log as well per your previous request.

cephalo
Sep 20, 2007, 04:37 PM
Ok, I just published 1.03a. This change is mostly for seven05 in hopes of finding the MP bug.

I noticed that in the dll, CvPlayer.setStartingPlot does not update the m_bStartingPlot member in CvPlot, so here's to hoping that this is important and might fix the problem.

Seven05
Sep 20, 2007, 09:32 PM
Well now I feel special :)

I still can't test it until Saturday though, but I'll keep you posted.

Seven05
Sep 21, 2007, 11:15 AM
Here's a quick one for you, I've been running this for some time. I adjusted it to force all players to start on the coast, otherwise a non-coastal start would typically mean starting one or two plots in from the coast since the landmasses are generally too thin to really start you in the middle of all land. It applies to all players, human and AI alike and also help prevent somebody starting in the middle of a large desert (although they can still start surrounded by mostly desert).


def findStartingPlot(playerID,bestArea):
gc = CyGlobalContext()
gameMap = CyMap()
player = gc.getPlayer(playerID)

player.AI_updateFoundValues(True)

iRange = player.startingPlotRange()
iPass = 0

while (true):
iBestValue = 0
pBestPlot = None

for iX in range(gameMap.getGridWidth()):
for iY in range(gameMap.getGridHeight()):
pLoopPlot = gameMap.plot(iX, iY)
if (pLoopPlot.getArea() != bestArea):
continue
if (pLoopPlot.getLatitude() >= 75):
continue

val = pLoopPlot.getFoundValue(playerID)

if val > iBestValue:

valid = True

for iI in range(gc.getMAX_CIV_PLAYERS()):
if (gc.getPlayer(iI).isAlive()):
if (iI != playerID):
if gc.getPlayer(iI).startingPlotWithinRange(pLoopPlot , playerID, iRange, iPass):
valid = False
break

#Only allow coastal starting plots
pWaterArea = pLoopPlot.waterArea()
if (pWaterArea.isNone()):
valid = false
valid = not pWaterArea.isLake()

if valid:
iBestValue = val
pBestPlot = pLoopPlot

if pBestPlot != None:
return gameMap.plotNum(pBestPlot.getX(), pBestPlot.getY())

print "player", playerID, "pass", iPass, "failed"

iPass += 1
if iPass > 100:
return -1

return -1

cephalo
Sep 21, 2007, 02:41 PM
Here's a quick one for you, I've been running this for some time. I adjusted it to force all players to start on the coast, otherwise a non-coastal start would typically mean starting one or two plots in from the coast since the landmasses are generally too thin to really start you in the middle of all land. It applies to all players, human and AI alike and also help prevent somebody starting in the middle of a large desert (although they can still start surrounded by mostly desert).



Once I lock down the MP bug I'm going to give starting plots a big overhaul with some tunable options. I want to find some way to give all players on a continent somewhat equal opportunity to all the good stuff it has. I suppose everyone likes to start on the coast, but I had a very fun game recently starting completely land locked on all sides in the middle of the desert. Luckily the starting plot normalizer gave me lots of marble so I could culture flip a coastal city with my wonders.

Coast only starts is a good option to provide though. I would also like to provide an option for different levels of fairness, including completely random and totally unfair. Also, maybe an option for different qualities of starting locations aside from fairness, like everyone with a bad, medium, or best starting location. It might be fun for players to have to look for the best areas instead of just owning them at the beginning.

I plan to go nuts with the starting location stuff.

Rael
Sep 22, 2007, 02:34 AM
I think this script is getting even better with each new release. Good job:)

However, there are two small glitches that bothered me right from the first version. One is the number of rivers and flood plains in the deserts. They make the poorest parts of map the best for settling. I don't usually get Sahara-like deserts with no cities around. I realize there are seasonal rivers on deserts but they shouldn't be treated as regular rivers.

The second glitch is in the screenshot. The rvier delta looks ugly and the x-marked tiles has no river on it (in regular map scripts it's always a river-tile). o-marked tile should also be flood plain.
Desert rivers without flood plains should also be generated just like in regular scripts. For example the upper parts of a desert river could have no flood plains.

cephalo
Sep 22, 2007, 10:03 AM
I think this script is getting even better with each new release. Good job:)

However, there are two small glitches that bothered me right from the first version. One is the number of rivers and flood plains in the deserts. They make the poorest parts of map the best for settling. I don't usually get Sahara-like deserts with no cities around. I realize there are seasonal rivers on deserts but they shouldn't be treated as regular rivers.

The second glitch is in the screenshot. The rvier delta looks ugly and the x-marked tiles has no river on it (in regular map scripts it's always a river-tile). o-marked tile should also be flood plain.
Desert rivers without flood plains should also be generated just like in regular scripts. For example the upper parts of a desert river could have no flood plains.

I have noticed that the delta glitch only happens to me when I regenerate the map without starting a new game. Other weird stuff happens also like floating resources and goody huts. It never happens to me the first time I generate the map. I wonder if some map finalization function needs to be called that isn't in some cases. Are you regenerating the map at all? The fix that works for me is to save your game, exit to the main menu and reload.

Also, in making floodplains, there's a function called CvPlot.isRiverSide. Basically I just make every desert square that answers 'true' to that function a floodplain. So it's very simplistic. I was thinking maybe I should tone that down, but it won't be trivial.

Rael
Sep 22, 2007, 02:51 PM
That was a regenerated map, but I think that even though it's only a display bug it's caused by the fact that the x-marked tile is not counted as river tile while it should be. I noticed it because I wanted to build a levee in the city placed on such tile and I couldn't. It doesn't happen always but when a river flows into a lake it's pretty common

cephalo
Sep 22, 2007, 06:40 PM
That was a regenerated map, but I think that even though it's only a display bug it's caused by the fact that the x-marked tile is not counted as river tile while it should be. I noticed it because I wanted to build a levee in the city placed on such tile and I couldn't. It doesn't happen always but when a river flows into a lake it's pretty common

You're right, that's definately a bug. I'll have to fix that. It must be that even though isNOfRiver and isWOfRiver are both false, the riverID still needs to be set to give the corners fresh water. Thanks for being persistant about insisting that it was a bug.

Seven05
Sep 23, 2007, 08:40 AM
I come bearing sad news :(

The MP bug still exists. That is if I host a game and you join while I'm in the staging room when we create the map we will be OOS (out of sync) and when you re-connect you're starting city will be somewhere very different.

Worse yet, I neglected to enable logging while we were going through trying to resolve a few other mod issues.

cephalo
Sep 23, 2007, 10:14 AM
I come bearing sad news :(

The MP bug still exists. That is if I host a game and you join while I'm in the staging room when we create the map we will be OOS (out of sync) and when you re-connect you're starting city will be somewhere very different.

Worse yet, I neglected to enable logging while we were going through trying to resolve a few other mod issues.

Did you have a chance to comment out the starting plot code? That's the thing that I needed most.

cephalo
Sep 23, 2007, 11:42 AM
That was a regenerated map, but I think that even though it's only a display bug it's caused by the fact that the x-marked tile is not counted as river tile while it should be. I noticed it because I wanted to build a levee in the city placed on such tile and I couldn't. It doesn't happen always but when a river flows into a lake it's pretty common

Hey Rael, I have a question for you. What are the stated requirements for a levee? I only use vanilla at this time, so it's hard for me to test things properly. In vanilla, on other map scripts, there would be no fresh water on the x-marked tile if that lake there was ocean instead of a lake. Did they change the rules for Warlords etc?

I have no idea why that graphical glitch upon regenerating is there, other maps don't have that problem. Why it is fixed upon reload is also a mystery to me.

MrPopov
Sep 23, 2007, 08:41 PM
requirements for levee is next to a river. A fresh water lake won't do it for you. The dutch dike on the other hand I believe can be built either next to a river, or coastal (since it also adds +1 hammer to water tiles).


BTW I really love the map script!!

cephalo
Sep 24, 2007, 06:41 AM
requirements for levee is next to a river. A fresh water lake won't do it for you. The dutch dike on the other hand I believe can be built either next to a river, or coastal (since it also adds +1 hammer to water tiles).


BTW I really love the map script!!

Thanks! One more quick question, when you use a different old map script with BtS, like Terra for example, will Raels x-marked square meet the requirement for a river? Or, does that only happen in the newer BtS map scripts?

Rael
Sep 24, 2007, 10:03 AM
Yes, they're always rivers, at least in all (old and new) scripts in BtS (don't know about Vanilla)

cephalo
Sep 24, 2007, 12:29 PM
Yes, they're always rivers, at least in all (old and new) scripts in BtS (don't know about Vanilla)

The function that determines river crossings and thus river plots is called updateRiverCrossings in the SDK dll. I'll post the code.


void CvPlot::updateRiverCrossing(DirectionTypes eIndex)
{
CvPlot* pNorthEastPlot;
CvPlot* pSouthEastPlot;
CvPlot* pSouthWestPlot;
CvPlot* pNorthWestPlot;
CvPlot* pCornerPlot;
CvPlot* pPlot;
bool bValid;

FAssertMsg(eIndex >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < NUM_DIRECTION_TYPES, "eTeam is expected to be within maximum bounds (invalid Index)");

pCornerPlot = NULL;
bValid = false;

switch (eIndex)
{
case DIRECTION_NORTH:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH);
if (pPlot != NULL)
{
bValid = pPlot->isNOfRiver();
}
break;

case DIRECTION_NORTHEAST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH);
break;

case DIRECTION_EAST:
bValid = isWOfRiver();
break;

case DIRECTION_SOUTHEAST:
pCornerPlot = this;
break;

case DIRECTION_SOUTH:
bValid = isNOfRiver();
break;

case DIRECTION_SOUTHWEST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST);
break;

case DIRECTION_WEST:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST);
if (pPlot != NULL)
{
bValid = pPlot->isWOfRiver();
}
break;

case DIRECTION_NORTHWEST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTHWEST);
break;

default:
FAssert(false);
break;
}

if (pCornerPlot != NULL)
{
pNorthEastPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_EAST);
pSouthEastPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_SOUTHEAST);
pSouthWestPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_SOUTH);
pNorthWestPlot = pCornerPlot;

if ((pSouthWestPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pSouthWestPlot->isWOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}

if ((pNorthEastPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pNorthWestPlot->isNOfRiver())
{
bValid = true;
}
}

if ((eIndex == DIRECTION_NORTHEAST) || (eIndex == DIRECTION_SOUTHWEST))
{
if ((pNorthEastPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}

if ((pSouthWestPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pSouthWestPlot->isWOfRiver() && pNorthWestPlot->isNOfRiver())
{
bValid = true;
}
}
}
else
{
FAssert((eIndex == DIRECTION_SOUTHEAST) || (eIndex == DIRECTION_NORTHWEST));

if (pNorthWestPlot != NULL)
{
if (pNorthWestPlot->isNOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}

if ((pNorthEastPlot != NULL) && (pSouthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pSouthWestPlot->isWOfRiver())
{
bValid = true;
}
}
}
}

if (isRiverCrossing(eIndex) != bValid)
{
m_abRiverCrossing[eIndex] = bValid;

changeRiverCrossingCount((isRiverCrossing(eIndex)) ? 1 : -1);
}
}



Basically, in order to consider diagonal motion a river crossing, you need two river lengths. According to this code, and correct me if I'm wrong because this is not a simple issue and I may very well be misreading this code, crossing diagonally across the mouth of a river is *not* considered a river crossing, although it really should be considered one.

In vanilla, I was able to verify this behavior on other maps. The CvPlot::isRiver() function checks to count of all river crossings that are precomputed by the above. Diagonal from a river mouth does not create fresh water, which means the CvPlot::isRiver() function returns false. Here's the code for CvPlot::isFreshWater().

bool CvPlot::isFreshWater() const
{
CvPlot* pLoopPlot;
int iDX, iDY;

if (isWater())
{
return false;
}

if (isImpassable())
{
return false;
}

if (isRiver())
{
return true;
}

for (iDX = -1; iDX <= 1; iDX++)
{
for (iDY = -1; iDY <= 1; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

if (pLoopPlot != NULL)
{
if (pLoopPlot->isLake())
{
return true;
}

if (pLoopPlot->getFeatureType() != NO_FEATURE)
{
if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).isAddsFreshWater())
{
return true;
}
}
}
}
}

return false;
}



The thing is, if they changed the rules for BtS, why would my map behave differently than other older maps like Terra? Did they publish new versions for the old map scripts? I gues the obvious solution for me would be to go out and buy BtS but I'm sooooo broke.

JP Vieira
Sep 24, 2007, 12:41 PM
very interesting

cephalo
Sep 24, 2007, 07:01 PM
1.04 is available. This is a pretty big update. No starting location stuff yet. Made the number of rivers in the world tunable. Also added a tuner for how quickly floodplains are made in desert rivers. Fixed the bug where floodplains weren't appearing on river corners. I still haven't been able to figure out why my river graphics get wonky when the map is regenerated without going back to the main menu. Saving and reloading should fix that.

I added an option to use either Python's random number generator or the one given by the getMapRand function. Interestingly, the character of the maps generated by each randomizer is very different from the other. The Python generator is vastly superior with 53 bit precision. The Civ rands packs a 32 bit rand into a 16 bit integer. Call me crazy, but I think the Python random creates much more organic looking maps. They both generate random maps, but the difference is like looking at paisley compared to looking at plaid. Switch back and forth to see for yourself.

I actually have alot of experience randomly generating stuff, it's been a hobby of mine for a long time. Psuedo-random numbers are a very weird science. It's shockingly easy to accidently find your processes 'in tune' with an otherwise highly random generator, making it completely un-random for the particular thing you are trying to use it for. One time I was making a heightmap for a project of mine, and I discovered that one of the variables I was randomizing was always an even number, never an odd. Very strange! I switched to a different generator and the problem went away. When you're creating fractal art such as these maps are, you can't skimp on your random generator.

The only good thing about the getMapRand is that hopefully, Seven05's MP bug will go away! Seven05, set the UsePythonRandom variable to 'False'. If that doesn't fix the MP bug, I don't think I have the skills to fix it.

Rael
Sep 25, 2007, 11:36 AM
I looked at the same part of code in BtS and it's a bit different. That's the reason for all the misunderstanding. Anyway, great update, congratulations:goodjob:

cephalo
Sep 25, 2007, 11:46 AM
I looked at the same part of code in BtS and it's a bit different. That's the reason for all the misunderstanding. Anyway, great update, congratulations:goodjob:

Someday I'll get BtS, and try to go for better compatibility.

MrPopov
Sep 25, 2007, 11:58 AM
I want to share a few screenshots from your map script that shows why I love this so much. The first shows a very interesting coast. It is evident that your tectonics method formed a ridge where the island formed.

http://forums.civfanatics.com/uploads/96168/PW1.jpg

The second image shows a very fertile area with a large lake. Almost every map has a lot of character and it makes it fun to explore.

http://forums.civfanatics.com/uploads/96168/PW2.jpg

BTW If you want I could send you some .py of some BTS map scripts if you want to compare, or is that a no no?

cephalo
Sep 25, 2007, 12:50 PM
Thanks for the compliments MrPopov. Ahh, smell those pine trees on the wind. Sometimes the best thing about Civilization is being away from it.

:lol: :lol: :lol: :crazyeye:

Do you know of another map script that generates it's own rivers for BtS? Most map scripts use the default river generator in some way.

Seven05
Sep 25, 2007, 09:35 PM
Did you have a chance to comment out the starting plot code? That's the thing that I needed most.
Wow, it hasn't been easy to connect to CF lately... anyway, yes we went OOS even with all of your starting plot functions commented out, although I neglected to have them re-connect to see if they ended up in a different plot.

As for the rivers, none of the official BTS scripts use custom river generation.

LDiCesare
Sep 26, 2007, 02:39 AM
Do you know of another map script that generates it's own rivers for BtS? Most map scripts use the default river generator in some way.
There's mine (Tectonics) which generates rivers 'backwards' (from sea to source). The river code is a bit of a mess that I'd change if I weren't so lazy, but you can always look at it.

cephalo
Sep 26, 2007, 06:51 AM
There's mine (Tectonics) which generates rivers 'backwards' (from sea to source). The river code is a bit of a mess that I'd change if I weren't so lazy, but you can always look at it.

How does your script work with BtS LDiCesare? Can you build a levee on Raels x-marked square in his screenshot? Another less permanent, but still annoying problem I'm having with the delta graphics only happens on lakes that have rivers going into them. Since you don't have that particular combo of features, I guess it just doesn't come up on yours. I studied yours quite a bit while learning the ropes. Thanks for all your hard work.

Wow, it hasn't been easy to connect to CF lately... anyway, yes we went OOS even with all of your starting plot functions commented out, although I neglected to have them re-connect to see if they ended up in a different plot.

As for the rivers, none of the official BTS scripts use custom river generation.

Try turning off the Python randoms in the future, I can't imagine what else it could be.

cephalo
Sep 26, 2007, 08:56 AM
So I've got my starting plot code all torn to pieces right now and I need some advice. This should take a couple of weeks I imagine because I'm generating starting plots in a completely different way and there's bound to be obstacles I can't even imagine right now.

In normal map scripts that come with the game, the climates are strewn about in a highly random way that makes most land masses fairly homogenous. You can be sure that wherever you start, you are never too far away from some productive map squares, and you have a good chance that you will have first dibs on some good land.

On my map script, continents have good parts and bad parts. If you start on some tiny grassland penninsula connected to a vast desert, many of your descendents might be eating sand beetles for a thousand years before they find another patch of green, and it might all be occupied by someone who started closer to the good lands.

Take the following scenario, lets say we have a continent where we would like to place two players. The continent has an area of grassland on one end, but the rest is hard scrabble desert with some scattered plains. You can build cities there to be sure, and there's some valueable resources, but you wouldn't want to start there.

Here's the big question, is it ok to start the two players in the grassland fairly close to each other, facing possible war in the warrior stage? Starting them any other way would be hugely unfair, as one player would likely place a city or two in the productive area before the other even knew where to look. Right now, I'm thinking that if I place them near each other with equal access to the continents value, it would be ok. Keep in mind that this scenario can also happen on very large continents with 4 or 5 civs.

How important is starting distance, and why is it important?

Seven05
Sep 26, 2007, 09:34 AM
Here's an off-the-wall idea...

Evaluate the 'value' of entire areas (landmasses) before defining old/new world areas. Things to consider for establishing a value would be peaks (no value), desert without flood plains (very low value), features (trees=good, jungle=bad) and so on. Then, once you have a value per landmass, and you know the size of the landmass you can calculate the average value per tile and space the players out according to that. So a large landmass with a low value per tile would have fewer players than a smaller landmass with a higher value per tile. You could also ensure that the 'old world' is a better overall landmass than the 'new world' or the other way around if you prefer.

For final plot selection there are a few things to consider. First, since the game will generate additional bonuses around starting plots and the advantage of starting on a coast with clams/crabs/fish is HUGE in the early game due to their commerce AND food bonus a coastal start doesnt need as much 'good' land in the area as a non-coastal start. Second, hills are nice for production but only if you also have enough food, so a starting position with a food bonus or two and multiple hills is very good while a start position with hills and only production bonuses is not as good. Starting in, or even close to tundra can be very rough as that likely means the majority of your territory will be useless until you get lumbermills up and running. Rivers are critical in deserts & plains, but not as important in grasslands or hilly areas.

Now the one thing that would be really nice, but I'm not sure if it's even possible, would be to place civs based on their starting techs. So if a civ has fishing, for one example, they should always start on a coast.

The inequality of starting plots is a big part of what makes the game fun, but it's also a big part of what makes the game frustrating. An in-game option for 'balanced' or 'wild' starting locations would be nice to have.

Edit: Missed the last question about starting distance :)
Starting distance is very important for a few different reasons. Nearby neighbors can be a threat if they're agressive or cornered with nowhere else to go. Nearby neighbors are a boon otherwise, the advantage of open borders and somebody to trade techs with is pretty big. So more important that the actual distance is the ability to establish contact and trade early. Of course if you start alone on a good landmass you'll do just fine, but the AI in the same situation may be crippled depending on which leader it is.

And, very quickly, since I'm a C++ guy, not a python guy... how do I turn off the python random?

LDiCesare
Sep 26, 2007, 09:37 AM
How does your script work with BtS LDiCesare? Can you build a levee on Raels x-marked square in his screenshot?
I should test but I think I probably can't. The lake plot is water and has no reason to have a river on its border, whereas I suppose in BtS, there may be a river hidden below the lake. Maybe world editing the tile to change it to grass would show a river?
Furthermore, one must be careful with the default scripts, as they add lakes and rivers after player placement, and the code being called late can cause some artefacts (like desert rivers with no floodplains).

cephalo
Sep 26, 2007, 09:41 AM
I'm particularly interested in ending this occurance as well.

X = Land, O = Starting Plot
............
...XOXXXOX..
..XX.....XX.
.XXXX.......
.XXXXXX.....
XXXXXXXX....
.XXXXX......
............


I see this alot on my map and it must stop. I think I know how to prevent it.

cephalo
Sep 26, 2007, 09:54 AM
I should test but I think I probably can't. The lake plot is water and has no reason to have a river on its border, whereas I suppose in BtS, there may be a river hidden below the lake. Maybe world editing the tile to change it to grass would show a river?
Furthermore, one must be careful with the default scripts, as they add lakes and rivers after player placement, and the code being called late can cause some artefacts (like desert rivers with no floodplains).

I think you might be able to actually. I'm big on text graphics today so I'll show you what I mean. I'm talking about corners across river mouths.

X = Land, x = non river intersection, r = river
XxX......
xxx......
XxXxX....
rrrrrr...
XxXxXxX..<---River Here?


I have disabled the normalize functions that add lakes and rivers, so they all should be added in a way that I intended.

cephalo
Sep 26, 2007, 10:04 AM
And, very quickly, since I'm a C++ guy, not a python guy... how do I turn off the python random?

The latest version has a global variable that I made just for you. It's called UsePythonRandom, and you can set it to 'False'. ;)

Seven05
Sep 26, 2007, 10:35 AM
Right... just saw 1.04 and read that (follow by a quietly whispered, oh crap) :)

khuxtable
Sep 26, 2007, 05:08 PM
I'm running Civ IV on a Mac (PPC). When I try PerfectWorld, even version 1.04a, I get no elevations. I get small lakes and some forestation, but the world is all grasslands and two-square-long rivers.

Any ideas?

-K

MrPopov
Sep 26, 2007, 07:39 PM
as far as starting location goes. I agree with Seven in that starting too close (ie warrior combat close) is bad. It just encourages the player to rush and can dictate the flow of the rest of the game to unfavorable results.

On the other hand though, unfavorable starts can end up being a very fun game with a unique and exciting story. It's hard to pin down the best solution but IMHO if someone wants a truly balanced game for competitive MP or HOF reasons, that's what the vanilla scripts are for. However if it is something you think you can tackle, add some options for it for things like balanced starting plots, new world/old world, etc. so if we want a random map still we can have it :)

cephalo
Sep 26, 2007, 10:49 PM
I'm running Civ IV on a Mac (PPC). When I try PerfectWorld, even version 1.04a, I get no elevations. I get small lakes and some forestation, but the world is all grasslands and two-square-long rivers.

Any ideas?

-K

Can you post a screenshot? The only time I've had that happen is when the script crashed in the middle of map creation. This map script is starting to become something of a beast, and it wouldn't surprise me if some machines on the lower end of things might not work well. Does the same thing happen every time? Do you get an error message? Also, try generating a duel size map first and work your way up. That might tell you if you have some kind of problem with computer resources.

Sto
Sep 27, 2007, 07:57 AM
You should ask AlanH for mac compatibility in this thread (http://forums.civfanatics.com/showthread.php?t=198619) . The bug occur probably with operator.attrgetter .

Tcho !

cephalo
Sep 27, 2007, 08:15 AM
You should ask AlanH for mac compatibility in this thread (http://forums.civfanatics.com/showthread.php?t=198619) . The bug occur probably with operator.attrgetter .

Tcho !

Thanks for the tip! Yikes, so Mac civ is using Python 2.3? Ouch. I'll try to work that in.

Seven05
Sep 27, 2007, 10:02 AM
And you thought the MP side was a pain ;D

I have finally tweaked & tuned the script almost to my own version of perfection, or more accurately to better work with my mod. The climate based terrain works like a charm, incidentally I saw you tried adding some noise to the rain to break up the banding, add that noise to the temperature map instead and you'll solve the banding without messing up the climate too much. Altitude based terrain is probably going in soon, not a big deal but since the data is there, why not use it? :)

I have a couple of issues I'd like to adjust a bit more, but I need your help since I don't fully understand how you're doing a couple things.

First, and most important to me, is desert rivers & lakes. Ideally, I would like to remove every lake that is surrounded by desert and disallow any rivers through desert terrain that don't terminate at the ocean. Is there a good way to trace a river backwards or would it be better to modify the flowmap before rivers are even generated?

The next thing I'd like to do is reduce the frequency of large inland seas. I don't want to simply fill them all in with land though. It would be ideal if I could fill some in, force channels out from others and if a channel is created plot out a few small islands inside the sea.

Both of these would help a bit with the overall gameplay in my mod. The deserts are critical since I use them to hold the majority of the key strategic resource (oil, iron and copper) and I only allow desert cities to be built on the coast or tiles with fresh water. The large number of lakes & rivers in the desert makes it too easy to gain access to all of the resources. The inland sea issue is more for strategic importance and to give the AI a helping hand since it doesn't understand that building a massive fleet of warships won't help them if they can't go anywhere.

Also, I don't know if you would want it or not but I added a few simple steps to the tectonics code so the generator has a chance of creating 'typical perfect world' maps, pangea maps (with no land at the poles) or mixed continents. And I added an oceanic divide to the initial heightmap generation to help ensure that there is some ocean separating the landmasses. Of course I kept everything random so you really have no clue what you're getting yourself into since thats the way I like to play.

Anyway, thanks again for the incredible script and the continued updates. I'll keep you posted on the MP issue when I have a chance to test it again.

cephalo
Sep 27, 2007, 10:43 AM
You're in for alot of work Seven05. I'll try to answer your questions.

Getting rid of desert rivers will also get rid of the lakes. The final riverMap in the RiverMap class is just like the flowMap, but with all non rivers set to rm.O. Any rm.L(Lake or Pit) you find you can check to see if it's in the desert, and if so you can follow the river backwards and erase each river length by setting it to O. No lake will be generated without the river there, when you see a lake without one, it's because the lake ate the river that caused it.

The large inland seas come from either the river system making a huge lake or else because one plate sunk below all the surrounding plates. In the first case, you can set LakeSizePerRiverLength to a smaller value. In the second case, you might increase the size tolerance for the initial lake filling, but you might end up with a very large swath of land if you go too far with that. The makeHarbor function will cause ocean to invade lakes to a degree of one map square. You might try to extend it to be more invasive.

The difficulty with some of this stuff you want to do is that on this map, the heightmap is the law of the land. Rain will go downhill, even if that is the middle of your continent, and the larger the continent, the more likely this will happen.

jmm
Sep 27, 2007, 11:03 AM
Great script, however I found a problem around the poles.

Sometimes the unpassable territory is overwritten by tundra or ice.



U=Unpassable t=tundra P=Peak w=water (ocean)

UUUUUUttPtUUUUUU
wwwwwttttttwwww
wwwwwttppwwwww
wwwwwttwwwwww


In addition sometimes the starting positions are on those small areas and the AI just builds a city in the top row, cutting the workable area to half and with only low value terrains, there is no much hope for the AI.

There is another noteworthy side-effect, there is a large number of resources put on the first row (copper, iron and uranium)

cephalo
Sep 27, 2007, 12:14 PM
Great script, however I found a problem around the poles.

Sometimes the unpassable territory is overwritten by tundra or ice.



U=Unpassable t=tundra P=Peak w=water (ocean)

UUUUUUttPtUUUUUU
wwwwwttttttwwww
wwwwwttppwwwww
wwwwwttwwwwww


In addition sometimes the starting positions are on those small areas and the AI just builds a city in the top row, cutting the workable area to half and only low value terrain.

There is another noteworthy side-effect, there is a large number of resources put on the first row (copper, iron and uranium)

Is the top row unpassable? I guess I never really checked that. The starting positions are going to be revamped. I'm right now neck deep in the craziest, hopefully Mac compatible, starting plot code the world has ever seen. Will it work? Is it even feasable? Nobody knows.

The resource code is all default placement. I have been forbidden to touch that as such things are supposed to be handled in the XML.

I remember the night I first published version 1.0. I said, "Ahhhhh, I'm finally finished!" Don't worry, If I can't fix the starting code, I can at least create Santa Claus as that civs UU.

Seven05
Sep 27, 2007, 02:35 PM
Is the top row unpassable?
No, but it is typically impassable Ice. I adjusted the terrain generation script to always force that top and bottom row as water myself, mainly for asthetic reasons.

The resource code is all default placement. I have been forbidden to touch that as such things are supposed to be handled in the XML.
You can actually do a bit without breaking the XML rules. The problem comes from non-standard resources, if you write custom resource placement any mod that adds custom resources won't be able to use your script. Of course you've already 'broken' custom features so it really shouldn't matter :)

I remember the night I first published version 1.0. I said, "Ahhhhh, I'm finally finished!"
Famous last words :)

Seven05
Sep 27, 2007, 02:45 PM
You're in for alot of work Seven05. I'll try to answer your questions.

Getting rid of desert rivers will also get rid of the lakes. The final riverMap in the RiverMap class is just like the flowMap, but with all non rivers set to rm.O. Any rm.L(Lake or Pit) you find you can check to see if it's in the desert, and if so you can follow the river backwards and erase each river length by setting it to O. No lake will be generated without the river there, when you see a lake without one, it's because the lake ate the river that caused it.
Forgive me since I'm not looking at the code right now, but is it easy to track the flowmap (like knowing which adjacent plot to check/modify). I remember bits of it vaguely, like the L and O parts, isn't the rest N,S,E,W? If so is it a matter of saying, "ok, this plot is a W so if I go one plot E I'm tracking the flow 'upstream'."

The large inland seas come from either the river system making a huge lake or else because one plate sunk below all the surrounding plates. In the first case, you can set LakeSizePerRiverLength to a smaller value. In the second case, you might increase the size tolerance for the initial lake filling, but you might end up with a very large swath of land if you go too far with that. The makeHarbor function will cause ocean to invade lakes to a degree of one map square. You might try to extend it to be more invasive.
Didn't you drop the code to clean up lakes, or is it just hidden now? The makeHarbor function is working very well right now, the problem is that I seem to have a bit of luck in getting seas surrounded by land that is two tiles thick, perhaps a quick change to the horbor code is all I need. Is that executed before or after the area lists are generated? If it's after it should be a simple matter to identify inland seas but if it's before I can work directly with the heightmap... Gah! :)

The difficulty with some of this stuff you want to do is that on this map, the heightmap is the law of the land. Rain will go downhill, even if that is the middle of your continent, and the larger the continent, the more likely this will happen.
Yeah, I tried some basic 'evaporation' code, but I wasn't happy with the results since it affected all of the rivers. Although I suppose I could run a check after the terrain is generated but before the rivers are to only apply evaporation in desert squares (I was using temperature & rainfall data before). The again, maybe my evaporation code was just flawed :)

cephalo
Sep 27, 2007, 03:25 PM
Forgive me since I'm not looking at the code right now, but is it easy to track the flowmap (like knowing which adjacent plot to check/modify). I remember bits of it vaguely, like the L and O parts, isn't the rest N,S,E,W? If so is it a matter of saying, "ok, this plot is a W so if I go one plot E I'm tracking the flow 'upstream'."
Yes, the riverMap works that way also. Keep in mind that when you go backwards, each plot might branch off to tributaries, so you'll have to put them on some kind of stack for deletion later. For each plot you think, "ok, who of my four neighbors is flowing into me?" If the answer is nobody, then you are done with that branch of river. Drastic stuff! Maybe theres a better way. Remember that the latest version allows you to control floodplain generation, so maybe you can render those rivers and lakes impotent.

Didn't you drop the code to clean up lakes, or is it just hidden now? The makeHarbor function is working very well right now, the problem is that I seem to have a bit of luck in getting seas surrounded by land that is two tiles thick, perhaps a quick change to the horbor code is all I need. Is that executed before or after the area lists are generated? If it's after it should be a simple matter to identify inland seas but if it's before I can work directly with the heightmap... Gah! :) I fill lakes right at the beginning during heightmap generation, with the idea that they will be recreated via the river system. The Areamap class that you speak of is general purpose, if you learn how to use it you can do something on your own concerning areas. I use it for several different things.

Yeah, I tried some basic 'evaporation' code, but I wasn't happy with the results since it affected all of the rivers. Although I suppose I could run a check after the terrain is generated but before the rivers are to only apply evaporation in desert squares (I was using temperature & rainfall data before). The again, maybe my evaporation code was just flawed :) I have an idea. Find the following code:


#Create average rainfall map so that each intersection is an average
#of the rainfall from rm.rainMap
for y in range(hm.mapHeight):
for x in range(hm.mapWidth):
i = hm.GetIndex(x,y)
avg = 0.0;
for yy in range(y,y-2,-1):
for xx in range(x,x+2):
ii = hm.GetIndex(xx,yy)
avg += rm.rainMap[ii]
avg = avg/4.0
self.averageRainfallMap[i] = avg


see what happens when you square 'avg'.

Change
self.averageRainfallMap[i] = avg

to

self.averageRainfallMap[i] = avg * avg


This might eliminate desert rivers altogether. If so you can try some other tweak on this value. This will steepen the curve, and if all rivers become diminished you can pump up the RiverThreshold global.

khuxtable
Sep 27, 2007, 11:08 PM
Here's a screen shot of a duel-sized map. I play on a 23" monitor at 1280x800. I can go up to 1920x1200, but then I'd need to move the monitor closer or put on my glasses. I'm lazy.

This isn't a low-end Mac. It's one of the last non-Intel Macs made. It has two dual core 2.5GHz G5 processors and 2GB of RAM. The graphics card is a GeForce 7800GT driving a digital Mac LCD monitor. I've got plenty of RAM. This is basically a server-class machine. It's my development system.

BTW, I'm a programmer, but not a Python programmer. I normally write in Java, C++, or Perl and develop database applications, so this is a bit out of my line, but I can probably learn to read Python. I've got a book.

I've never really felt like the Mac ports are that great, but they're what I can get. I do have a 2.4GHz P4 mobile Dell laptop sitting around the house, but I gave my Windows CivIV away to a friend.

Oh, I play with the Blue Marble textures, so they'll look a bit different from the standard textures.

Thanks,

-K

Seven05
Sep 27, 2007, 11:21 PM
I have an idea. Find the following code:


see what happens when you square 'avg'.

This might eliminate desert rivers altogether. If so you can try some other tweak on this value. This will steepen the curve, and if all rivers become diminished you can pump up the RiverThreshold global.
That actually works very well, except I had to reduce the RiverThreshold, not increase it. At 2.0 and above I would have maybe a single river on the entire map, at 1.0 there were more but they were all 1-2 tiles at most, at 0.2 it's very good (for my taste) with plenty of rivers around the map and only a few scarce rivers in the desert. At any rate, that's certainly a more effecient method rather than cycling through the entire map another three of four times to trace rivers :)

I had the chance to test it in MP except I was running into a problem. When setting it to not use python random the map was flat grassland, no water, hills, peaks or anything but grassland and a bunch of long rivers. I have a feeling the mapRand isn't precise enough for the changes I put into the heightmap. Next time I get a chance I'll load up an un-modified version of your script with the python random disabled.

khuxtable
Sep 27, 2007, 11:27 PM
You should ask AlanH for mac compatibility in this thread (http://forums.civfanatics.com/showthread.php?t=198619) . The bug occur probably with operator.attrgetter .

Tcho !

Well, your "full of resources" scripts work fine... I've been using them for months with no problems.

I read through the thread and didn't notice any references to operator.attrGettr. What does it do? What should we be doing instead? The script definitely uses it, I think four times. Twice with 'size' and once with 'ID', and once with 'altitude'.

-K

Sto
Sep 28, 2007, 02:12 AM
I read through the thread and didn't notice any references to operator.attrGettr. What does it do? What should we be doing instead? The script definitely uses it, I think four times. Twice with 'size' and once with 'ID', and once with 'altitude'.

You can try that waiting for cephalo update ( windows use python 2.4 and Mac use python 2.3 where operator.attrGettr is not defined ) :

#self.areaList.sort(key=operator.attrgetter('size' ),reverse=True)
tpList = [ [ item.size , item ] for item in self.areaList ]
tpList.sort()
tpList.reverse()
self.areaList = [ item[1] for item in tpList ]

#continentList.sort(key=operator.attrgetter('size' ),reverse=True)
tpList = [ [ item.size , item ] for item in continentList ]
tpList.sort()
tpList.reverse()
continentList = [ item[1] for item in tpList ]

#continentList.sort(key=operator.attrgetter('ID'), reverse=True)
tpList = [ [ item.ID , item ] for item in continentList ]
tpList.sort()
tpList.reverse()
continentList = [ item[1] for item in tpList ]

#lakeNeighbors.sort(key=operator.attrgetter('altit ude'),reverse=False)
tpList = [ [ item.altitude , item ] for item in lakeNeighbors ]
tpList.sort()
lakeNeighbors = [ item[1] for item in tpList ]


For cephalo , if you want to know if you're running into a MAC OS and use a global ( because this method is not very fast compare to operator.attrGettr )

if (sys.platform == 'darwin'): MacOS = True


Tcho !

cephalo
Sep 28, 2007, 07:07 AM
I've never really felt like the Mac ports are that great, but they're what I can get. I do have a 2.4GHz P4 mobile Dell laptop sitting around the house, but I gave my Windows CivIV away to a friend.

Oh, I play with the Blue Marble textures, so they'll look a bit different from the standard textures.

-K

I understand the problem now khuxtable, it will be fixed in the next version. I just have to strip out all Python 2.4isms.


I had the chance to test it in MP except I was running into a problem. When setting it to not use python random the map was flat grassland, no water, hills, peaks or anything but grassland and a bunch of long rivers. I have a feeling the mapRand isn't precise enough for the changes I put into the heightmap. Next time I get a chance I'll load up an un-modified version of your script with the python random disabled.


It's an ok random generator, what you are seeing is a map crash. If you use any randoms yourself, be sure to use PWRand. Hopefully it's not a crash that I just failed to test for.

cephalo
Sep 28, 2007, 07:15 AM
You can try that waiting for cephalo update ( windows use python 2.4 and Mac use python 2.3 where operator.attrGettr is not defined ) :

#self.areaList.sort(key=operator.attrgetter('size' ),reverse=True)
tpList = [ [ item.size , item ] for item in self.areaList ]
tpList.sort()
tpList.reverse()
self.areaList = [ item[1] for item in tpList ]

#continentList.sort(key=operator.attrgetter('size' ),reverse=True)
tpList = [ [ item.size , item ] for item in continentList ]
tpList.sort()
tpList.reverse()
continentList = [ item[1] for item in tpList ]

#continentList.sort(key=operator.attrgetter('ID'), reverse=True)
tpList = [ [ item.ID , item ] for item in continentList ]
tpList.sort()
tpList.reverse()
continentList = [ item[1] for item in tpList ]

#lakeNeighbors.sort(key=operator.attrgetter('altit ude'),reverse=False)
tpList = [ [ item.altitude , item ] for item in lakeNeighbors ]
tpList.sort()
lakeNeighbors = [ item[1] for item in tpList ]


For cephalo , if you want to know if you're running into a MAC OS and use a global ( because this method is not very fast compare to operator.attrGettr )

if (sys.platform == 'darwin'): MacOS = True


Tcho !

Thanks Sto, I'll be using the crazy 'lambda' thing from the Python Wiki. So

lakeNeighbors.sort(key=operator.attrgetter('altitu de'),reverse=False)
will be
lakeNeighbors.sort(lambda x,y:cmp(x.altitude,y.altitude))

I'm not too concerned about time, I figure that you only have to generate it once per game, and a good map is worth the wait.

khuxtable
Sep 28, 2007, 10:51 PM
Thanks Sto, I'll be using the crazy 'lambda' thing from the Python Wiki. So

lakeNeighbors.sort(key=operator.attrgetter('altitu de'),reverse=False)
will be
lakeNeighbors.sort(lambda x,y:cmp(x.altitude,y.altitude))

I'm not too concerned about time, I figure that you only have to generate it once per game, and a good map is worth the wait.

I just wanted to say that sto's changes worked for me. Thanks, Sto!

I understand what a crazy lambda thing is from my lisp and perl background. Have fun!

-K (for Kathryn)

cephalo
Sep 29, 2007, 09:04 AM
I just wanted to say that sto's changes worked for me. Thanks, Sto!

-K (for Kathryn)

Good news!

Update coming soon. The new starting code works great, except for dropping people into the ocean once in a while. Hopefully, I'll have a publish this weekend.

Seven05
Sep 30, 2007, 12:27 AM
It's an ok random generator, what you are seeing is a map crash. If you use any randoms yourself, be sure to use PWRand. Hopefully it's not a crash that I just failed to test for.
No idea here... I double checked and every check for a random value that I use is using your PWRand.random() or PWRand.randint(). Anyway, setting it to use the map rand vs. the python rand does the trick in MP games- no more OOS issues when using your base script.

cephalo
Sep 30, 2007, 06:49 AM
No idea here... I double checked and every check for a random value that I use is using your PWRand.random() or PWRand.randint(). Anyway, setting it to use the map rand vs. the python rand does the trick in MP games- no more OOS issues when using your base script.

Excellent!

As for your map crash, if you enable the Python error messages you should get a popup explaining why it crashed. I don't remember how to set that up, because I set mine up years ago. Also, if you have logs enabled you can check PythonErr.log.

cephalo
Sep 30, 2007, 12:51 PM
Ok, I had to go back to the drawing board for my starting area enhancements, so I made a mini-publish to eliminate the Mac bug and the multi-player bug. Seven05, Sto showed me how to detect a network game, so you shouldn't have to fool with UsePythonRandom anymore.

My starting area finder was interesting. I calculate a list of all the best possible city starts on a continent and made a table of the path distances between them all for easy lookups. This makes it easy to evaluate the value of each starting city when all players are placed. Then, I did an exhaustive search of every possible combination of city plots and starting locations for a fair result. The results are *exactly* fair. The processing time takes, on a small continent with a couple players just a few seconds. On a large 'pangea' type continent with 200 cities and 13 players I estimate the processing time to be about 1,000 years(not an exaggeration). Since people only live to around 80 or 90 years old, you can see that this technique is not entirely feasable.....*cry*:cry:

Even if they make some kind of medical breakthrough, by that time you could probably just pick up a copy of Civ 102 and play the world war 7 scenario, which would probably be waaaay better. :old:

I will not give up! I have a cunning plan!:wallbash:

khuxtable
Sep 30, 2007, 04:24 PM
My starting area finder was interesting. I calculate a list of all the best possible city starts on a continent and made a table of the path distances between them all for easy lookups. This makes it easy to evaluate the value of each starting city when all players are placed. Then, I did an exhaustive search of every possible combination of city plots and starting locations for a fair result. The results are *exactly* fair.

Yeah, that's an NP complete algorithm. It has nasty scaling. I suggest some shortcuts.

-K

cephalo
Sep 30, 2007, 06:30 PM
Yeah, that's an NP complete algorithm. It has nasty scaling. I suggest some shortcuts.

-K

Here's a shorthand explanation of the problem.

1's are starting locations, and digits are possible cities on a continent.

111110000000000000000000000000000000000000000

I know the distance between each city, and I can use that to determine which starting location is closest to what cities. I also know the local value of each city, that way I can add the value of each city to the starting location that claims it by virtue of distance. I'm trying to avoid some starting locations being blocked into a bad peninsula like what I had posted earlier.

Any time I move one of those 1's, I have no idea how to predict how the value of the the other 1's will end up. I tried simply improving the 1 that had the worst value, but curing his problem was highly likely to ruin someone else's starting position. Stepping through a subset of the possibilities sometimes worked, but if the algorithm completed in failure I ended up with little better than random starting locations.

So I made this nifty little algorithm that slid the little bits like an abacus to every possible location exactly once. It was fun to watch it spin through the combinations. The problem is that every time you add a digit the time factor goes up about 20%, and each time you add a 1 it almost doubles. So unless you're using tiny maps with 4 players, worst-case behavior is a game breaker.

I didn't get a chance to actually test how often worst-case behavior happens, I would think that the larger the problem the more combinations that satisfy fairness would arise, but I can't count on that. I could set an iteration limit, but if that limit is reached then you've waited 10 minutes for bad starting locations that could have been better placed