PerfectWorld3

My random tinkering didn't seem to do much, and PWRand is not suffering from any problems that would require a pause after seeding. I still decided to purge the first random number generated but it probably isn't accomplishing anything.

ChangeLog:
-Changed how the average height around a river junction was getting determined.
-Removed local copy of elevationMap from riverMap. It wasn't necessary since elevationMap is Global and there were no changes being made to the local copy.
-Fixed and Optimized SiltifyLakes(). It should no longer be possible for a lake to be left behind.
-Raised the iteration limit of SiltifyLakes() to 10,000,000 and changed the error status to just log a message instead of crashing the map. It seriously should not be possible to hit anywhere near 10 million iterations without there being an infinite loop, seriously.

:smoke:

Edit: I have now uploaded my update to the Steam Workshop http://steamcommunity.com/sharedfiles/filedetails/?id=171848014&searchtext=
 

Attachments

  • PerfectWorld3(v5b).7z
    22 KB · Views: 4,127
So I made a couple of script changes to an older version, and tweaked a lot of constants. The constants aren't all that important to share, but I will share the two changes I made to get the script to be a little more toward what I wanted.


First, I modified the all tiles next to a mountain tile are hills script. It tends to generate a LOT of hills that dont really add much. Instead I made it flip a tile only if it were next to 2 mountain tiles. I fould this worked a lot better, and opened up more flat land in mountain areas that made them actually useful.

Code:
	-- Guarantees that any tile above sea level that's touching a mountain is a hill
	-- This makes mountain ranges look more natural... CLP from bobert13's suggestion

	local mountainFound = 0
	 for y = 0, gridHeight - 1,1 do
		for x = 0,gridWidth - 1,1 do
			local i = elevationMap:GetIndex(x,y)
			local plot = Map.GetPlot(x, y)
			if not elevationMap:IsBelowSeaLevel(x,y) then
				if plot:GetPlotType() == PlotTypes.PLOT_LAND then
					local tiles = elevationMap:GetRadiusAroundHex(x,y,1)
					for n=1,#tiles do
						local xx = tiles[n][1]
						local yy = tiles[n][2]
						local nPlot = Map.GetPlot(xx,yy)
						if nPlot:GetPlotType() == 

PlotTypes.PLOT_MOUNTAIN then
							mountainFound = mountainFound + 1
						end
					end
					if mountainFound >= 2 then
						plot:SetPlotType

(PlotTypes.PLOT_HILLS,false,true)
					end
					mountainFound = 0
				end
			end
		end

Pretty minor mod, but I think it actually makes a big difference for gameplay I think. Those solo mountains dont automatically get ringed by a bunch of hills.

I have noticed that this doesnt convert marshes, not sure what is going on with that, but it wasnt glaring enough to me to bother to fix.

Second thing I did was I wanted to be able to generate Hemispheres reliably divided by ocean.

To do that, I first toggled up the east and west attenuation map constants.

Second thing I did is added code for a prime merdian map constant. Yeah i know the prime merdian actually goes through England, but you come up with a better name. :p

First the constants I put in and the values I set existing constants to:


Code:
	--These attenuation factors lower the altitude of the map edges. This is
	--currently used to prevent large continents in the uninhabitable polar
	--regions. East/west attenuation is set to zero, but modded maps may
	--have need for them.
	--DEFAULTS = .75, .15, .75, .15
	mconst.northAttenuationFactor = 0.60
	mconst.northAttenuationRange = 0.15 --percent of the map height.
	mconst.southAttenuationFactor = 0.60
	mconst.southAttenuationRange = 0.15

	--east west attenuation may be desired for flat maps.
	--DEFAULTS = 0, 0, 0, 0
	mconst.eastAttenuationFactor = 0.60
	mconst.eastAttenuationRange = 0.15 --percent of the map width.
	mconst.westAttenuationFactor = 0.60
	mconst.westAttenuationRange = 0.15

	--Prime meridian attenuation
	mconst.primeAttenuationFactor = 0.60
	mconst.primeAttenuationRange = 0.15

These are open to tweaking of course.

Then I modified the attenuation function adding this on the end:


Code:
	local primeM = map.width / 2 
	local lowM = primeM - map.width * mc.primeAttenuationRange
	local highM = primeM + map.width *mc.primeAttenuationRange
	local pAttenuation = 1.0
	local vFromM = x - primeM
	local maxvFromM = primeM-lowM
	if x >= lowM and x <= highM then
		pAttenuation = mc.primeAttenuationFactor + (math.abs(vFromM)/maxvFromM) * (1.0 

- mc.primeAttenuationFactor)
	end

	return yAttenuation * xAttenuation * pAttenuation

Im also thinking of adding a constant to offset the meridian. Maybe a random offset, maybe a static one.
 
Marshes are features so they're placed after plot types. However, marshes require flat land so if the script places a marsh on a hill, it replots it to flat land.

Also, here's an example of how I'm randomly generating a center rift offset in my unreleased tectonic derivative:
Spoiler :
Code:
	local riftMod = PWRandInt(math.floor(W/32), math.ceil(W/10))
	local riftPosNeg = PWRandInt(0,1)
	local centerRift = W/2
	if riftPosNeg == 0 then
		centerRift = centerRift + riftMod
	else
		centerRift = centerRift - riftMod
	end
 
Marshes are features so they're placed after plot types. However, marshes require flat land so if the script places a marsh on a hill, it replots it to flat land.

Also, here's an example of how I'm randomly generating a center rift offset in my unreleased tectonic derivative:
Spoiler :
Code:
	local riftMod = PWRandInt(math.floor(W/32), math.ceil(W/10))
	local riftPosNeg = PWRandInt(0,1)
	local centerRift = W/2
	if riftPosNeg == 0 then
		centerRift = centerRift + riftMod
	else
		centerRift = centerRift - riftMod
	end
Thanks, new to lua, and havent done any programming in a while, so this is a help.

Ported over the hill/mountain adjust from the previous versions. Discovered that the get circle function was unfortunately incompatible with the above sea level call in that script, so had to pull over the unoptimized function to get a hex's neighbors from a previous version. Oh well, works fine. Also poped the central trench mod, but havent put the moving merdian/rift in yet. Want to test it out gameplay wise first.

One thing Ive been thinking about is the issue of long river systems running into single tile lakes. If a watershed is leading to a river, and that river runs into a depression that is lower then the surrounding area, filling that area in a small lake makes sense. Then either one of two things would happen. If the depression were a large enough bowl, then it would keep filling that bowl until the evaporation on the area matched the amount of water feeding it, and you would wind up with an inland sea or a large inland lake. Or the depressed area would fill up until the water table rose high enough that it found an "exit", and the river started flowing from the lake. Of course over time you would expect erosion to carve a shorter path to the sea, and the lake to then drain to the sea faster out a canyon. So overtime no lake.

However, I do think there are a shortage of lakes in the map script, and I do think there are some optimizations that could be done with lakes and rivers in the map script, but Im not sure what they are yet. Im going to think about this and see if I can come up with something clever.
 
You're saying you tried porting your foothills routine into v5b? If so, you can quickly calculate the (x,y) coordinates from the index value that my optimized functions return.

Code:
local x = i%W
local y = (i-x)/W

All i (a.k.a index) is, is a 1-dimensional coordinate. I'd also change the double "for y; for x loops" out for a single "for i=0,self.length-1,1 do" statement.

Lastly, because my spiral iterators return an index instead of coordinates, you'd change this:
Code:
					local xx = tiles[n][1]
					local yy = tiles[n][2]
					local nPlot = Map.GetPlot(xx,yy)
to this:
Code:
					local ii = tiles[n]
					local nPlot = Map.GetPlotByIndex(ii)

Using index values is less convenient and takes a little bit of time to get used to, but it speeds up the code dramatically because it reduces table ops, and more often than not you have to have the index but it's only in some cases that you have to have the coordinates. All of the custom methods in the script (like FloatMap:IsBelowSeaLevel()) can even be re-written to use indexes instead of coordinates (and this particular method actually requires an index value and is only using x,y to calculate that value so it could be sped up by converting it!).

You really don't see much of the lake scenario you're describing because the script actually fills in depressions in the elevationMap and then when it's getting ready to plot rivers it ensures that every river junction (read "corner of a hex") has a lower junction adjacent to it so that rivers can't get stuck and end before they hit some body of water. That being said, lakes on rivers are tricky because there appears to be no reliable way to trick the graphics engine into drawing a river flowing from a body of water. I and at least one other modder here are looking into possibilities for this, but we've pretty much hit a dead end on multiple fronts.
 
Would it be much work to convert this script to a pangaea-style map? Because I like pangaea...
 
Would it be much work to convert this script to a pangaea-style map? Because I like pangaea...

You can greatly increase the chance of rolling a Pangaea by tweaking the main constants yourself. They're at the top of the script which can be opened with any text editor. TwistMaxFrequency and TwistVar are probably the two that will have the greatest affect on what you want.
 
Hm, regardless of which values I enter for those and other paraeters, a pangaea continent seems to always be confined to either the northern or southern hemisphere. How can I change that?
 
You've probably got TwistMinFrequency too low. Keep in mind that the numbers can be as finite as you'd like them to be (up to at least 15 digits after the decimal, if not more).

Edit, I'm working on presets for v6 of my updated PW3 and Pangaea is one of the ones I wanted to get in. I haven't really played with tweaking to get it right. One thing I may look into is implementing Yshift so that the landmass will always spawn with some water north and south of it (The game's Pangaea script uses X and Y shift). This probably won't be a very simple process as there's a lot of code that may need to be changed for me to get a decent shifted Pangaea. :eek:

Years ago, Pouakai was working on some presets though I don't know whatever came of it.

Edit: If you have the Civ V SDK installed, using WorldBuilder to spawn maps, instead of doing it in-game, speeds up the process of tweaking the constants dramatically.
 
Hm, I tried a lot of settings but I just can't seem to get a decent looking pangaea map that isn't also completely devoid of smaller islands. :(
 
Hm, I tried a lot of settings but I just can't seem to get a decent looking pangaea map that isn't also completely devoid of smaller islands. :(

Do you mind sharing what you've got so far? Either PM me or post your entire mainConstants section in a /spoiler tag and I'll take a look at it today.
 
In terms of pangaea vs islands and rugged coastlines, I found these settings to be the best compromise:
Code:
mconst.twistMinFreq = 0.01
mconst.twistMaxFreq = 0.01
mconst.twistVar = 0.005
mconst.mountainFreq = 0.2
Also, in order to get a more blob-like pangaea as opposed to a very long east-west continent, I found that modifying the east/west attenuations helps by squishing everything into the middle:
Code:
mconst.eastAttenuationFactor = 0.25
mconst.eastAttenuationRange = 0.50
mconst.westAttenuationFactor = 0.25
mconst.westAttenuationRange = 0.50
However, that also seems to lead to even fewer islands than already. :undecide:
 
In terms of pangaea vs islands and rugged coastlines, I found these settings to be the best compromise:
Code:
mconst.twistMinFreq = 0.01
mconst.twistMaxFreq = 0.01
mconst.twistVar = 0.005
mconst.mountainFreq = 0.2
Also, in order to get a more blob-like pangaea as opposed to a very long east-west continent, I found that modifying the east/west attenuations helps by squishing everything into the middle:
Code:
mconst.eastAttenuationFactor = 0.25
mconst.eastAttenuationRange = 0.50
mconst.westAttenuationFactor = 0.25
mconst.westAttenuationRange = 0.50
However, that also seems to lead to even fewer islands than already. :undecide:

I wouldn't use the east west attenuation except for maybe to guarantee an ocean rift (I'd use a range of like 0.06 and set the factor to be very strong [lower is stronger]). Another thing you can do to promote more blob-like landmasses is alter the XtoYRatio. I'd comment out the line where I use a formula and try constant values between 0.9 and 1.1 for extremely blob-like features. To get more islands you're going to have to bump up twistVar; probably by quite a bit. I'll see if I can get something like what you want here shortly.

Edit: Try this out and see if it's closer to what you're looking for:
Spoiler :
Code:
		-------------------------------------------------------------------------------------------
		--Landmass constants
		-------------------------------------------------------------------------------------------
		mconst.landPercent = 0.30 		--Percent of land tiles on the map.
		mconst.hillsPercent = 0.60 		--Percent of dry land that is below the hill elevation deviance threshold.
		mconst.mountainsPercent = 0.94 	--Percent of dry land that is below the mountain elevation deviance threshold.
		mconst.mountainWeight = 0.4		--Weight of the mountain elevation map versus the coastline elevation map.
		
		--Adjusting these frequences will generate larger or smaller landmasses and features. Default frequencies for map of width 128.
		mconst.twistMinFreq = 0.01 		--Recommended range:[0.02 to 0.1] Lower values result in more blob-like landmasses, higher values make more stringy landmasses, even higher values results in lots and lots of islands.
		mconst.twistMaxFreq = 0.016		--Recommended range:[0.03 to 0.3] Lower values result in Pangeas, higher values makes continental divisions and stringy features more likely, and very high values  result in a lot of stringy continents and islands.
		mconst.twistVar = 0.01 			--Recommended range:[0.01 to 0.3] Determines the deviation range in elevation from one plot to another. Low values result in regular landmasses with few islands, higher values result in more islands and more variance on landmasses and coastlines.
		mconst.mountainFreq = 0.5		--Recommended range:[0.1 to 0.8] Lower values make large, long, mountain ranges. Higher values make sporadic mountainous features.
		
		--These attenuation factors lower the altitude of the map edges. This is currently used to prevent large continents in the uninhabitable polar regions.
		mconst.northAttenuationFactor = 0.15
		mconst.northAttenuationRange = 0.25 --percent of the map height.
		mconst.southAttenuationFactor = 0.15
		mconst.southAttenuationRange = 0.25 --percent of the map height.

		--East/west attenuation is set to zero, but modded maps may have need for them.
		mconst.eastAttenuationFactor = 0.15
		mconst.eastAttenuationRange = 0.175 --percent of the map width.
		mconst.westAttenuationFactor = 0.15
		mconst.westAttenuationRange = 0.175 --percent of the map width.
		
		--Hex maps are shorter in the y direction than they are wide per unit by this much. We need to know this to sample the perlin maps properly so they don't look squished.
		--local W,H = Map.GetGridSize()
		--mconst.YtoXRatio = math.sqrt(W/H)
		mconst.YtoXRatio = 0.6

It still needs a little tweaking (especially tundra, getting way too much tundra and not enough plains), and I did need to use attenuation to constrain the landmass. It's using my lowered settings for rough terrain so in that regard it's a lot closer to a default civ mapscript than it is to PW3.

I'm not sure if there's a way to make the world circumnavigable via island chains before Astronomy but IMO, it really shouldn't be. I could implement a routine to come back and plot islands intentionally, though I generally prefer the more organic method of using the elevation algorithms and whatnot over a forced method. When I get my derivative released, it should be more capable of consistent Pangaeas than Perlin Noise seems to allow.
 
Probably this has been asked a dozen times - anyway: does this script work on a Mac too?

I've never explicitly heard of anyone using it on Mac, though there's no reason it shouldn't work if put in the equivalent of \My Documents\My Games\Sid Meier's Civilization V\Maps\ folder.
 
I extracted the file from post 481, and it seems to contain just Perfectworld.lua, but not PerfectWorld3(v1).modinfo

That's correct. If placed at the location I mentioned above, it shouldn't need the .modinfo nor should it need to be activated in the Mod Browser for it to appear in your list of maps (It may only appear in the Advanced Setup menu though, and not on the main setup window).
 
could you provide your tweaked files? I would rather not have to read this whole thread to find all the tweaks to make to the original files.
I do not have the internet at home and the library has a 1 hour limit on internet time.
 
could you provide your tweaked files? I would rather not have to read this whole thread to find all the tweaks to make to the original files.
I do not have the internet at home and the library has a 1 hour limit on internet time.

Post #481
 
Top Bottom