Idraluna Archives

The Great Antarctic Hexcrawl Pt. 5 - Growing Hexes, Pruning Ambitions

This is my own version of lore24, an admittedly over-ambitious attempt to procedurally generate a 128,000 43,000-hex crawl for my homebrewed far-future Antarctica, Antibor. Part 1, Part 2, Part 3, Part 4 and 4b.


I remapped Antibor with 10 mile hexes. Here's the new, coarser map:

The bigger hexes are primarily a concession to feasibility. I've been drafting a hexfill procedure (more in a future post) & long story short, this change cuts the total number of hexes down from 128,000 to around 43,000, reducing the number of unique (i.e. not just a monster or settlement) hexfills I'll need from around 13,000 to maybe 5,000. Fewer hexes also means faster processing time for GIS analysis, the possibility of actually printing the key, etc.

With that acknowledged, I'm aware of several examples of OSR bloggers making strong cases for smaller hexes (i.e. <6 mi.) or pointing out problems with big hexes, and I (so far) haven't seen many cohesive defenses of large hexes beyond 'it's less fiddly / more convenient'. So I've drafted a few very rough arguments for big hexes, if for no other reason than to convince myself that this change isn't solely rooted in laziness. (To be clear, I think the linked posts are convincing and well-argued; mainly just coping lol)

Haphazard Cases for Big Hexes

D&D has never really been a realistic depiction of medieval Europe. It's pretty well-established that D&D as originally conceived was a western in 14th c. drag (not unlike the pulp S&S that inspired it). So while I'm a sucker for reading posts about the average spacing of medieval castles and villages, it's not the be-all-end-all for a D&D campaign. One could simply accept that a game with wizards in it doesn't need to be realistic (lame), or draw on a variety of inventive lore conceits to justify a world where points of interest have greater spacing than the real world (cool & fun).

Large, epic distances are fun. LOTR-style journeys across a whole continent are cool. Epic, sweeping vistas are cool. Tense encounters when there's nobody around for miles and miles are cool:

Ranging over empty, ruinous, apocalyptic landscapes is cool.

All of these things play nicely with big hexes. Packing tons of detail into a tiny area feels virtuous, but also kind of rinky-dink, lacking in grandeur and ambition. Idk.

Hex size sets a procedure/content/game-time ratio. This one's purely down to preference, but dense, tiny hexes run into the issue of 'Die Hard Time'. Hydra's Grotto lists the fact that a 3-mile hex can be traversed in one hour as a point in its favor. The math is tidy, but just how many adventures do I want players to be able to have before lunchtime? And if POIs are spaced out enough to avoid 'Die Hard Time', how much procedural tracking of empty hexes do I want to endure to reach them? Maybe this is very un-OSR of me but I just don't want to track movement hour-by-hour.

There are simpler tools for dealing with the 'inside' of a hex than 'more, smaller hexes'. Implicit in some 'small-hex' arguments is the idea that a hexmap should be defined by the densest features in the 'territory', and I guess I disagree. Skerples' Siena post observes that within a single six-mile hex there is plenty of adventure to be had:

[In the towns within Siena's 6 mile hex:] Mercenary armies camped there. Rulers fled, monks plotted, bishops pronounced doom, fugitives hid, and rebellious factions raised banners.

But that basic idea applies to any hex that includes a dungeon, for example. Someone else (can't find the link atm) pointed out that a 6-mile hex is equivalent to the area of Manhattan. How many hexes would be appropriate to map Manhattan?

Rather than keying a whole map with the same detail as its densest features, it's probably easier to set hex size according to the average spacing of features in the imagined landscape & designate specific hexes as containers for a more complex keyed description. For example, binning content into Landmark, Hidden, and Secret categories, inserting a Pointcrawl, or even just drawing a regular non-abstracted map.

Big hexes leave room for restocking. Fully exploring the 30-sq.-mile area of even a 6-mile hex would be extremely difficult, straining the realism of a guaranteed keyed encounter. But this has advantages; making it difficult to fully explore or 'clear' a hex allows for some narrative flux & makes things like random monster encounters more believable (as with interstitial dungeon rooms).

Misc. thoughts: Dungeons are tidy, enclosed spaces that work well as both skirmish wargame scenarios and non-linear narrative sandboxes; it's possible to cognitively track everything 'interesting' in a dungeon (or fake doing so convincingly), so the correspondence between the imagined world and its representation in text and conversation are tight. Even the ruptures exist in a sweet spot where the imagined narrative and arbitrary rules used to simulate it meet in a rich, charming interplay. So far, (afaik) no method for representing overland scenarios is quite as satisfying.

At the end of the day, the dream is what I'll call INDEFINITE OPEN-ENDED DIEGETIC FRACTAL CARTOGRAPHY where interesting things are rendered in perfect detail, boring ones can be effortlessly elided, and players are given absolute freedom & interesting, informed choices. Short of that, every overland cartographer has to butcher some part of the territory to fit it onto their map lest it be yielded up to the inclemencies of sun and winters.

A pointcrawl offers a more 'organic' representation of relative location but lacks the perceived objectivity & freedom of a hexmap. Assumptions about the narrative (i.e. what's an interesting destination & what's off-limits) are baked in to the presentation in a more direct way than on a hexmap, which might be why they seem to be more popular with the storygame-influenced NSR scene.

Hexes, on the other hand, enforce a uniformity of scale that can never perfectly represent a heterogenous landscape.1 They offer an impression of objective measurement but must still embrace simplifications & abstractions that carry implicit narrative assumptions. However, these assumptions may feel more open-ended and neutral than those of a pointcrawl.

Large hexes dial up the level of abstraction and strain realism, but if one is willing to roll with that, they allow for a workable balance of epic scale, player freedom, and procedural streamlining.

I'm making a hexmap of Antibor because I can, because the format works well with my GIS skills and the way I think. I want players to be able to range across the whole continent without too much procedural baggage, and I want to conjure up imagery of vast, barren landscapes littered with crumbling traces of Irð's past glories. 10 mile hexes will be adequate for this.

On a final, tangential note, I also want to see if I can sidestep some of these hexcrawl debates by playing around with fuzzy diegetic boundaries, Mythic Underworld-style. Hexes will be called 'cantons' & acknowledged in the narrative as legally recognized units of land. Gradually, these imaginary boundaries will have reshaped the landscape: the Citadel arcologies will be hexagonal megastructures that completely occupy a canton, ancient landlords re-channeled rivers to run along hexagonal borders, coastal communes reclaimed their cantons from the sea Dutch-style, etc. It's very silly but I'm having a lot of fun with it.


Adjusted Travel Rules

This is just a rough sketch of a simplified travel procedure based around 10-mile hexes. Given the enormous map, I want players to be able to roam with minimal procedural baggage. Thus, no dividing the day into 'watches', no separate tracking of food, water, and animal feed, etc.

Properties of 10mi Hexes

Base Movement Rate

Flat Hilly Rugged
Road or well-worn trail 3 hexes/day 2 hexes 2 hexes
Open (steppe, savannah, desert, chaparral) 2 hexes 2 hexes 1 hex
Forest, taiga, jungle, xenoformed 2 hexes 1 hex 1 hex

Rates should be interpreted as 'max distance that day'; if you've gone two hexes along a flat road, you could go one more hex along a flat road but couldn't enter a hilly road hex.

Being mounted on a 'regular' mount like a pack lizard, nesodon, or merychip provides +1 hex. An 'elite' mount like a destrier or war raptor provides +2 hexes.

Forced marches allow moving +1 hex but incur exhaustion penalties (consuming an extra ration allows a save to avoid). Mounts that fail their saves roll a d6, collapsing for the rest of the day on 5-6, crippled/hobbled on 3-4 and dead on 1-2.

Encounters

Rolled for every hex.

Weather

Rolled for every hex. 1: Inclement, reduce all movement rates by 1 and roll exhaustion saves if in an intemperate climate (monsoon, blizzard, sandstorm) 2-4: Visibility impeded if wet (-1 to d6 threshold for lookouts and navigators), or heat/cold effects if dry (exhaustion save) 5+: Clear

Roll a d6 for jungle, xenoformed, a d8 for wet temperate areas, a d10 for dry temperate areas, and a d12 for desert and steppe.

Camping

One roll overnight for nocturnal encounters. Lookouts may be posted, sacrificing their ability to retore HD but providing a 2-in-6 chance of waking the party before an encounter.

Supply Consumption

Numbers account for ease of foraging & grazing pack animals.

Flat Hilly Rugged
Temperate (savannah, chaparral, temperate forest) 1 1 2
Intemperate (steppe, desert, taiga, jungle) 2 2 3
Hostile (xenoformed) 3 3 4

Anyone assigned to the 'navigator' role rolls a d6 to avoid getting lost. Chances given are of moving in the desired direction.

Flat Hilly Rugged
Road or trail - - 1-in-6
Open (steppe, savannah, desert, chaparral) 5-in-6 4-in-6 3-in-6
Forest, taiga, jungle 3-in-6 2-in-6 2-in-6
Xenoformed 2-in-6 2-in-6 1-in-6

Exploring a Hex

Players always run across the main keyed encounter for a hex (assumed to lie somewhere visible or along the path of least resistance through the hex). Players always receive a clue if the hex has any hidden content. Secret contents must be discovered via treasure maps and rumors.

Navigation rolls can also be made when devoting a day to exploring the interior of a hex. 'Hidden' contents require one success, 'Secret' contents require two. Successes are cumulative across days of exploration.


Revamped Roads

Remapping to bigger hexes gave me a chance to revisit how I was aligning roads to hex centers. Instead of using the wonky QGIS Snap to Geometry tool, I wrote this little R script that works along the same lines as the code I used to snap rivers to hex edges.

It works by looping through pairs of adjacent hexes and checking if a road crosses their shared edge. (There are some floating point issues with my layer so I had to write my own intersection detection that works within a 1m tolerance). If so, it adds a road segment between the centers of the hexes sharing that edge.

### Fixing roads
##### USE HEX EDGE CROSSINGS!
rails <- vect(file.path(mapdir, 'Rail_nework.gpkg'))
roads <- vect(file.path(mapdir, 'Prefec_roads.gpkg'))

road_hexes <- vect(file.path(mapdir, 'Road_hexes.gpkg'))
road_hex_centroids <- centroids(road_hexes)
adjacencies <- adjacent(road_hexes) %>% as.data.frame() %>%
  filter(from != to) %>%
  mutate(from2 = pmin(from, to), to2 = pmax(from, to)) %>%
  group_by(from2, to2) %>% slice_head(n=1) %>% ungroup()


road_hex_geom <- geom(road_hexes) %>% as.data.frame()
road_hex_centroids_geom <- geom(road_hex_centroids)

road_segs <- vect(geom(road_hexes[1,])[1:2,], crs=crs(road_hexes), type='lines')
rail_segs <- vect(geom(road_hexes[1,])[1:2,], crs=crs(road_hexes), type='lines')

for (i in 1:nrow(adjacencies)){
  print(paste(i, 'out of', nrow(adjacencies)))
  adj_pair <- adjacencies[i,]
  geoma <- geom(road_hexes[adj_pair$from])
  geomb <- geom(road_hexes[adj_pair$to])
  # get their shared edge
  edgepts <- geoma[NULL,]
  for (j in 1:6){
    pta <- geoma[j,]
    for (k in 1:6){
      ptb <- geomb[k,]
      #print(pta, ptb)
      if ((abs(pta['x']-ptb['x'])<1)&&(abs(pta['y']-ptb['y'])<1)){edgepts <- rbind(edgepts, pta)}
    }
  }

  shared_edge <- vect(edgepts, crs=crs(road_hexes), type='lines')


  # check if a road crosses their shared edge
  if(!is.empty(intersect(rails, shared_edge))){
    print('rail crossing_detected')

    geom_to_link <- rbind(road_hex_centroids_geom[adj_pair$from,c('x','y')], road_hex_centroids_geom[adj_pair$to,c('x','y')])

    rail_edge <- vect(  # make edge
      geom_to_link,
      crs = terra::crs(road_hexes),
      type = 'lines'
    )

    rail_segs <- rbind(rail_segs, rail_edge)
  }

  if(!is.empty(intersect(roads, shared_edge))){
    print('road crossing_detected')

    geom_to_link <- rbind(road_hex_centroids_geom[adj_pair$from,c('x','y')], road_hex_centroids_geom[adj_pair$to,c('x','y')])

    road_edge <- vect(  # make edge
      geom_to_link,
      crs = terra::crs(road_hexes),
      type = 'lines'
    )

    road_segs <- rbind(road_segs, road_edge)
  }
}

Leave a comment on Reddit


  1. Perhaps a world in which the antithesis between town and country has been abolished is the only truly ideal subject matter for a hex map.

#DIY #GIS #antibor #game-design #lore24