September 14, 2020

Resources XXII: Reserves

I will be going through material sources in an effort to quantify which areas would be most suitable for population generation. To do this I'll rely on the concept of reserves.

On the Higher Path blog [subscription needed], Alexis calls out reserves as:

So let's use the word Reserves to describe wealth as it occurs in the wilderness, and resources to describe wealth as that which the civilised parts of the kingdom actively exploit.

I'll use it in a slightly different way: the level of unexploited resource in the wilderness which may be exploited. Not all wells are equally deep, for instance.

Let us consider the noble auroch. This animal occurs in the following Koppen climates: Aw; As; Am; Csa; Csb; Csc; Cwa; Cwb; Cwc; Cfa; Cfb; Cfc; Dfa; Dfb. As a large mammal, we may also assume it needs at least 1 point of water drainage in a hex to survive (probably a low estimate). This yields the following distribution:

Nothing interesting so far. Let's apply some Perlin noise.

Now, aurochs are not found in every place where they might possibly be. For the sake of illustration, let's do 50% (cattle are pretty ubiquitous, I'd expect this to be on the high side for a reserve).

We are left with a number between 0 and 1 detailing the relative level of abundance of the wild reserve of aurochs. What that level is can then be derived separately and scaled. For example, wild cattle generally form herds of about 10 animals, with some instances of up to 184 head/3400 hectares. This is less than a reference per hex: about 0.3 ref/20hex. Obviously, once these herds are domesticated, their size will increase, so the exact relationship between the raw reserve and its resource equivalent will need to be defined.

On the other hand, I could simply tie the 0-1 relative abundance to the maximum developed reference density, which for this resource is 733 ref/20hex (assuming 100% utilization which is obviously a false assumption). Much to think about.

The advantage of using Perlin noise is the fact that it is reproducible given the same inputs: if these are defined for each commodity, then the reserves sort themselves out.

September 10, 2020

The Juvenis Adventure

For the last few weeks, I've been lucky enough to be a player in Alexis' reboot campaign, the Juvenis Adventure.

The experience has been quite something even in early stages. Play-by-post is a tricky mistress, and even more so when the players stretch across many time zones. Alexis' game is hard work at times, but it's different from every campaign I've ever been in.

My fresh-off-the-boat elven fighter was thrown more or less immediately into a fight which far outclassed me. The party had last left off fighting demon toads and attempting to close a gate to Hell itself. Oh sure, I've been in (and run) similar scenarios before; so what was so different about this one?

The difference crystallized in a single moment: we attempted to swing an icy gate shut and a demon teleported right next to me to prevent us from moving it. My Level 1 fighter had no magical weapons, an overly cautious demeanor towards combat, and no health to speak of. I knew this demon could kill me and cast my soul into Hell, probably all in the same turn.

And there's the difference: I had to decide to stand and fight (and protect my friends) or to run and maybe save myself. I felt real fear in the pit of my stomach - my character had no backstory to save, no valuables to protect - a coldness in my heart weighing my options. I had to overcome an actual emotion, to swallow my pride and put my body in the breach.

That is something you won't find in any other game.

August 7, 2020

Koppen and Holdridge

The last step in climate is to apply the Koppen or Holdridge mappings, based on the local temperature and precipitation properties.

I'm not at all convinced that Holdridge is working for me. But I like to keep it around just in case.
Holdridge key
Holdridge
Overall, Koppen seems more intuitively correct.
Koppen key
Koppen
A nice mix of types of terrain. For some reason I feel like Koppen is easier to work with. Maybe it's the palette. Using all this data, I assign a terrain value (such as forest or savanna). This lets me make a map which is more human friendly.

Terrain
There's a lot of savanna here, as it turns out. I can live with that.

I think the next thing I'll dive into is individual resource research. I want to start gaming at some point in the next ten years, so it's necessary to get some actual stuff a party could use (as well as the historical simulation for background). That'll be a project in itself.

August 1, 2020

Temperature VI: PET

I have previously addressed potential evapotranspiration here, so I don't really need to address it again beyond a few minor updates.

January
July

July 31, 2020

Temperature V: Big Picture

To find the temperature, I created functions that more or less followed the guidelines from this post. The best way I found was to have slightly different functions for each category.

'normal': lambda x: -42.5 * (x / 90) ** 2 + 25 if x >=0 else -20 * (-x / 90) ** 2 + 25,
'hot': lambda x: -42.5 * (x / 90) ** 2 + 25 if x >=0 else -20 * (-x / 90) ** 4 + 25,
'cold': lambda x: -42.5 * (x / 90) ** 1.5 + 25 if x >=0 else -20 * (-x / 90) ** 1 + 25,
'cont': lambda x: -63 * (x / 90) ** 2 + 25 if x >=0 else -56.5 * (-x / 90) ** 2 + 25,
'cont+': lambda x: -63 * (x / 90) ** 2 + 25 if x >=0 else -20 * (-x / 90) ** 2 + 25

Then I just flip it around (reverse the latitude) in the opposite season. The common theme remains: the important thing is that this code exists and can be easily applied.
The next step is a small blur to smooth out the transitions, and then I lapse the temperature up based on height (-3.5 F per 1000 ft).

January
January

Looks reasonable to me, although I probably should fiddle with the map colors so that the hot and cold areas pop a bit more.

July 27, 2020

Temperature IV: Coastal Influence

Coastal and continental influences help make the temperature distribution more interesting.

With winds and current temperatures well in hand, should be easy enough to find these areas where cold and hot temperatures (here defined simply where the current is colder or warmer than the default temperature) are distributed near the coast.

In these plots, blue and red represent cold and hot influences. Yellow represents continental influence (large landmasses) and dark yellow is "continental plus."
January
July
...Quite a lot of cold current influence, to be perfectly honest. I was expecting more of a mix. This tells me I might need to do some work on my current temperature algorithm.

For now, however, this part of the code works. Garbage in, garbage out, so I will need to return to the "in garbage" at some point soon.

The other explanation is that the large landmass across the equator prevents true recirculation of the warmest waters. The poles, which generate the cold currents, are relatively unchallenged. So perhaps there is an explanation here where the code remains ok.

July 24, 2020

Rain II

Now we can begin to get closer to the meat of climate.

I begin with the base precipitation value at the coasts: \[P_h = p_0 \cdot \left(\exp\left(\frac{-\left(\ell - s\right)^2}{\sigma^2}\right) + \\ \frac{1}{2} \cdot \exp\left(\frac{-\left(\ell - 45 s\right)^2}{\sigma^2}\right) + \frac{1}{2} \cdot \exp\left(\frac{-\left(\ell + 45 - s\right)^2}{\sigma^2}\right)\right) \frac{(90 - \ell)(90 + \ell)}{90^2}\], where $p_0$ is the max precipitation value (127 mm/mo), $\ell$ is the latitude, $s$ is a seasonal parameter (15 in summer, -15 in winter), and $\sigma=19.5$.

Wet vs dry coasts (summer)
Throw in a box blur (n=3, radius=2) and baby, you got a stew goin'.


January
July

So far I like these results more than the first time around. Onward!

July 22, 2020

Wind VIII: Over the Land to Skye

Once we have established the wind pattern over the sea, we can determine the effect that the topography has on those winds.

First, I get a list of all winds blowing on or near the coasts. For each of those, I take the projected vector of the wind onto each neighboring hex. If the angle of the projected vector is $<90^\circ$, I know that it's at least in the right direction to catch a bit of that wind.

From there, I determine $dh$, which is the difference between the heights of the two hexes, source and target. If $dh$ is downhill ($dh<0$), there's no change. Otherwise, the turnaside angle $\theta$ is calculated as \[\theta = \frac{90 \exp\left(r \cdot \mathit{dh}\right)}{90 + \left(\exp\left(r \cdot \mathit{dh}\right) - 1\right)}\], where $r=2\log(89)/5000$ is calculated such that the wind will be totally turned aside $90^\circ$ when the slope is 5000 ft or more.

This is one of those areas that I've still not managed to tweak completely to my satisfaction, but it will be good enough to use for precipitation.

Angle of wind vectors (not speed) in summer

Wind VII

I'm looking over my old code and wondering what on earth I actually did to make this work.

Or whether it worked at all.

Allegedly, I used a curl function to boil the pressure down into a wind value (wind rotates around pressure centers, this makes sense). But I had gotten that initial pressure from a hand-drawn map on GIMP, and that's what I'm trying to get away from in this latest attack.

I tried to fiddle with getting the gradient but the implementation of a discrete gradient on a hex grid was somewhat problematic. However, this value may be useful later on in determining the length of the wind vector - winds on a steep pressure gradient will naturally be stronger.

The angle is another matter. This is where I really thought the gradient would help (and maybe it would on a different grid or even map layout). I ended up doing something much simpler: "walk" around the edge of the major pressure cells, correcting for direction based on the Coriolis effect, then (predictably) use IDW to fill in the rest of the map.

a quarter million objects has more of an effect on performance than you might think

For now, I am not box-blurring these values, so the transitions are still a little choppy. My plan is to apply the effect of the topography on the wind vectors and then smooth it out, so that everything lines up more nicer.

July 21, 2020

Pressure II

Update from here.

This time around, since I'm avoiding all manual input as much as possible, I can programmatically generate the pressure bands, at least a rough approximation of them.

The first step is pretty simple, I just apply the rules from this post to hexes which meet the correct criteria.

Then to smooth it out, I apply a box blur with a radius of 10 hexes to the pressure values (which are scaled between -1 and 1). I do this 3 times to approximate a Gaussian blur. Since I'm doing this on a hex grid, I haven't yet figured out any of the clever optimization tricks that are available for this approximation on a square grid.

January (winter in the north)

July (summer in the north)

For my next trick, I will try to avoid memory leaks while calculating wind flow.