|    .  ___  __   __   ___ .  __      __   __        __   __   __      
|    | |__  |__) |__) |__  ' /__`    /__` /  \  /\  |__) |__) /  \ \_/ 
|___ | |___ |  \ |  \ |___   .__/    .__/ \__/ /~~\ |    |__) \__/ / \ 
⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∽⋅∼⋅∽⋅∽⋅∽⋅∽⋅

Cairn Realmify log 3

Abstract

I want to automate the Cairn second edition map creation guide[0] to produce pure text maps, to integrate with my preparation notes easily. Previously[1], I've manually transcribed an existing map to see how that would look like then tried to improve the formatting. In this log, I want to apply the analogue method in a manual digital way. That way, I'll feel how well we can program this or not.

Log

There is actually quite a lot in the generation procedure that is not geographical. It start with the theme for the region. Rolled a 12 and a 1. Our region will thus have a religious character and ambition for bounty. Maybe a region where different localities compete for funds to renovate their respective temples?

Then it continues with resources. 17 and 6. Abundance of "vessels", scarcity of knowledge. Maybe interpret vessel as glass making or pottery. Scarcity of knowledge, maybe the religion calls for frequent libation, to put those vessels to good use. Everyone being frequently hammered might put a limitation to their motivation for education.

Then factions. Let's do three. Rolls are: {10,14,14,13}, {7,17,12,17}, {9,17,18,7}.

Let's give them names before we roll the advantages. There's a table for that too. I'll pass the details. The results are hilarious.

Let's adapt these a bit because no way I can say that with a straight face.

Less is more. Let's roll the advantages of these fine folks.

The Assembly has an 18. Four advantages:

The Guild of the Moon has a 5. Only one advantage:

The Horde has a 6. One advantage also:

This paints quite a picture. Now for objectives and obstacles.

The Assembly wants to establish a new order (9) but require a specialist of an uncommon sort (19).

The Guild of the Moon wants to destroy something (5) but it must be carried out in extreme secrecy (18).

The Horde wants to ascend to a higher plane (1) but an alliance with an enemy must first be brokered.

I won't translate that in full factions yet as what I want to focus on is what comes next: the geography. But it was sure fun and gives me a lot of ideas. I love this generation procedure.

Landmarks. I don't have a sheet of paper, so the position will be determined by rolling 4 d6, to compose (1-66,1-66) coordinates. It's arbitrary, but should serve us alright.

There will be four landmarks and associated terrain types.

To make my life easier, I'll edit this in LibreOffice then extract it to csv and print it out as a big text block. Wow. 66 lines is a lot of text. Dear improbable reader, I won't impose you to scroll and scroll to read my humble dev log. Just imagine the thing if you please.

Now, the idea of the terrain is that once you have the landmarks, you can roughly draw markings between them to define how much space they take each. How do we go about that programmatically? Basically through Voronoï cells, which I will approximate today. The resulting borders are okish. Let's continue.

Now the problem of waterways comes up. The idea is to roughly draw from higher elevation to lower elevation and wing it. Works great in the analogue world. How do we get something more procedural out of it? One way would be to:

Repeat the procedure as many times as needed. Not perfect, but let's try it out and learn something. From my understanding, altitude wise: A (Thickets) < C (Hills) < B (Bluffs) < D (Fells).

Ergo, let's pick a random position in D, then C, then B, then A. I'll do it by hand because it's getting late and doing domain determination by hand sounds like a hassle. To handle the connections, I go to the domain boundary in a straight line. Then if I need to change to match the alignment of the other point, I do it at the boundary with a straight turn.

My brain wants to do forking rivers and co. My brain is not to be trusted, that's something any person could edit in the map later on.

There are weather settings afterwards, that I will ignore for the moment to focus on geography. As I probably should have the faction things, come to think of it. Now, we have the points of interest.

The first one is the heart. It's supposed to be close to a water source. Let's determine it as follows. We take the center of the map then look for the closest free space (euclidean distance) that is close to a river. That will be noted with a 0.

Now we need to roll for other points of interests. It is suggested that they are between 3 and 8. Let's pick 5. First we roll the position as (d6d6,d6d6) then the category with a d6 (settlement/waypoint, curiosity, lair, dungeon). Then there's a table requiring two d20 rolls.

I'll give them numbers 1 to 5, given that the heart was 0.

Alright, we now need a way to do roads and paths. There is a "Draw Paths" section in the guide. With path features and three categories: road, trail, wilderness route. It is recommended to start with the heart. There is less randomness and more decisions required here. So let's do the following instead:

We connect each node to its 2 closest neighbours as per the Hamming distance. If there is an equality, connect the first two that came up regardless. If the first closest neighbour is closer to the second neighbour than the original node, don't connect it to the original node. We start in the top left corner and parse nodes left to right, top to bottom. If one of the neighbours found during the Hamming distance search is already connected, connect to the connected road element that is closest to the node being analyzed, as per the Hamming distance once again. Finally, landmarks do not count as nodes. Only points of interest, as in the example map. If the path goes through it, don't erase the landmark.

If a river comes up, go through it unless it is a corner, in which case do one side step in a random direction.

Very wordy, but what can you do. It yields:

(4<->5),(5<->0),(0<->1),(2<->3),(3<->5)

Let's densify things for waypoints/settlements/the heart. If one of the four spaces next to it are free and closer to a road in direct line according to the Euclidean distance than their connected neighbour, it gets connected. The connection points gets d6 rolled: 1-4 curiosity, 5-6 waypoint.

We have one such point. I rolled a 2. (9,1): Enormous Fist, Abandoned Vessel. It will be number 6. This adds (0<->6),(5<->6),(6<->3) instead of (5<->3).

Let's decide that connections between two settlements/waypoints are always roads. Otherwise, it's a d6 with 1-2 wilderness route, 3-4 trail, 5-6 road. Then for the features, it's a d20,d20 as usual. We get:

In theory, I should now indicate which is hidden or "conditional" (?). I think that we'll leave that aside for the moment. I feel this is something for the Warden to decide. The road layout is there, changing its type shouldn't be an ordeal.

I guess I can classify some of the feature as blocking/obstacle, like the boulders. It looks like most of the conditions in the table are hindrances though so it makes it difficult to decide. I think that some positive events would be neat. I think I'll add my own later on, like filled with nicely fragrant flowers or having cool shiny stones or a neat brook.

There is a travel time determination system, which I believe it is best to set aside for the moment. I feel it is best left in the hands of the Warden based on the paths that are rolled.

Alright, now time to condense the whole map by removing redundant columns or rows. A column or row is redundant if any pair has the same elements. Terrain elements don't count.

This yields:

░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
░░░░░░╔═════════╗▓▓▓▓▓▓
░░░░░░║▓▓▓▓▓▓▓▓▓║▓▓▓▓▓▓
░░░╞══╝▓▓▓▓▓▓▓▓▓║▓▓▓▓▓▓
░░░░░░▓▓▓▓▓▓▓▓▓▓║▓▓▓▓▓▓
░░░░░░▓▓▓▓▓▓▓▓C▓║▓▓▓▓▓▓
░░░░░░▓▓▓▓▓▓▓▓▓▓║▓▓▓▓▓▓
░░░░░4────┐▓▓▓▓▓║▓▓▓▓▓▒
░░░░░░░▓▓▓│▓▓▓▓▓║▓▓▒▒▒▒
░░░D░░░▓▓▓│▓▓▓▓▓║▓▒▒▒▒▒
░░░░░░░▓▓▓│▓▓▓▓▓║▓▒▒▒▒▒
░░░░░░░█▓▓│▓▓▓▓▓╚══╗▒▒▒
░░░░░████▓│▓▓▓▒▒▒▒▒║▒▒▒
░░░░░████▓5─┐▒▒▒▒▒▒║▒B▒
░░░░░█████│▓│▒▒▒▒▒▒║▒▒▒
░░░░░█████6─0────┐▒║▒▒▒
░░░░░█████│█╔════│═╝▒▒▒
░░░░░█████│█║▒▒▒▒│▒▒▒▒▒
░2─┐░█████│█║████│▒▒▒▒▒
░░░│░█████│█║████│▒▒▒▒▒
░██3──────┘█║████│█▒▒▒▒
░█████A█╔═══╝████│██▒▒▒
░███████║████████│█████
████████║████████1█████
████████║██████████████

Which I feel can be condensed more: If two row/columns are equal except for landmarks/points of interest, you get to remove them. It yields:

░░░░░╔═════════╗▓▓▓▓▓
░░░░░║▓▓▓▓▓▓▓▓▓║▓▓▓▓▓
░░╞══╝▓▓▓▓▓▓▓▓▓║▓▓▓▓▓
░░░░░▓▓▓▓▓▓▓▓C▓║▓▓▓▓▓
░░░░4────┐▓▓▓▓▓║▓▓▓▓▓
░░D░░░▓▓▓│▓▓▓▓▓║▓▒▒▒▒
░░░░░░█▓▓│▓▓▓▓▓╚══╗▒▒
░░░░████▓│▓▓▓▒▒▒▒▒║▒▒
░░░░████▓5─┐▒▒▒▒▒▒║▒B
░░░░█████│▓│▒▒▒▒▒▒║▒▒
░░░░█████6─0────┐▒║▒▒
░░░░█████│█╔════│═╝▒▒
░░░░█████│█║▒▒▒▒│▒▒▒▒
2─┐░█████│█║████│▒▒▒▒
░░│░█████│█║████│▒▒▒▒
██3──────┘█║████│█▒▒▒
█████A█╔═══╝████│██▒▒
███████║████████1████

I think it can be condensed a bit more:

░░░░░╔═════════╗▓▓▓▓▓
░░╞══╝▓▓▓▓▓▓▓▓▓║▓▓▓▓▓
░░░░░▓▓▓▓▓▓▓▓C▓║▓▓▓▓▓
░░░░4────┐▓▓▓▓▓║▓▓▓▓▓
░░D░░░▓▓▓│▓▓▓▓▓╚══╗▒▒
░░░░████▓5─┐▒▒▒▒▒▒║▒B
░░░░█████│▓│▒▒▒▒▒▒║▒▒
░░░░█████6─0────┐▒║▒▒
░░░░█████│█╔════│═╝▒▒
2─┐░█████│█║████│▒▒▒▒
██3──────┘█║████│█▒▒▒
█████A█╔═══╝████│██▒▒
███████║████████1████

How can I formalize what I did? Well, the characters where different but the types where the same. Then there is more complex stuff like river turns and road turns that are on otherwise empty rows/columns. These I feel would be a bit harder to do automatically. Maybe it's ok to leave some latitude for the Warden to edit the map.

Nonetheless, this procedure that we have run manually appear to yield something serviceable. Let's try to automate this recipe next time, it will be fun!

References

[0] The Setting Seed/Ream creation procedure
[1] the previous dev blog.

⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∼⋅∽⋅∽⋅∼⋅∽⋅∽⋅

home
posts
about