Idraluna Archives

The Great Antarctic Hexcrawl pt. 7b - Murdicog's Manse (Testing the Random Dungeon Generator)

St. Weirlund's Folly, my stocking procedure test site, has a Dungeon at hex 269-269. I wrote about my dungeon generator in parts 4 and 4b, but where I left off the generator was lacking code to specify monsters & assign room dressings. So in this post, I'll describe the generator's finishing touches and then examine the resulting output.

Finishing the Generator

I amended the code to prefer bigger dungeons. Realizing how big even one prefecture is & given the rough rate of one dungeon/prefecture, it feels wrong to generate dinky 15-room dungeons. The new average is around 45-50 rooms.1

Origin

I wrote up the following list to roll on. I tend to envision these dungeons as gonzo 'mythic underworld' rather than 'Gygaxian naturalism', so I'm not gunning for coherent history & ecology, but it still helps to have a prompt.

>>Ruin_type
Starship wreck ([Starship_type])
Necropolis
Laboratory ([Lab_type])
Exultant villa
Crypt^3
Swallowed One bio-complex
Power plant ([Power_plant_type])
Transit tunnels
Cosmodrome
Archive
Interstellar comms tower
Museum of a forgotten autochthonous nation
Prison
Extrasolarian shrine
Tomb^4
Breeding vat complex
Magical workshop
Factory
Mine
Missile silo
Trench network
Munitions plant
Natural caverns^5
Survival bunker
Abandoned village
Abandoned agrodome
Abandoned wizard's manse
Unknown^10
Castle
Pleasure palace
Temple
Sewer system
Kobellin earthdome
Mysterious obelisk of [Monolith_material]
Mysterious sphere of [Monolith_material]
Mysterious cube of [Monolith_material]
Mysterious pyramid or [Monolith_material]
Castle^5
Temple
Colosseum
Puzzle palace
Art museum
Cloning facility
Vault^3
Wunderkammer
[Ruin_type] and [Ruin_type]^15
Panopticon
Ruined war construct
Elder Thing city^3

Monsters

For a long time I've been avoiding having to write up proper encounter tables, be it by hand or procedurally. In the bestiary file, I've been assigning relative weights in three underground strata: 'abyssal', 'limnetic', and 'profundal' without a clear idea of how they work.

I was tired when working on this so I decided to keep things simple: Limnetic: 1-4, Abyssal: 5-8, Profundal: 9+. To assign a monster to a room, pick randomly, weighted by the category corresponding to the room's level. Done.

Since the link between monster HD and stratum weights is vibes-based rather mathematical, this tends toward an unbalanced and very 'gonzo' dungeon, discussed further below.

Dressing

For room dressings & traps I whipped up the following lists. I'm finding that extrapolating from disparate concrete details is more fun than trying to improvise from abstract information. Thus, most entries are things I can directly read off to players, whether or not I have an underlying rationale for why they're there.

I'll definitely keep adding to it over time. Note that the recursive [Dungeon_dressing] and [Dungeon_dressing] entry means that some rooms will generate with two or more features.

>>Dungeon_dressing
Unfurnished^30
Bookshelves ({empty|decayed|history|religion|pulpy fiction|technical manuals|alchemy|heresy|financial records})
Logic engine mainframe
Torture devices ({medieval|futuristic})
Mordengard entrance
Statue of [Statue_of]
Fountain ({clear water|brackish goo|dry})
Shrine to [Icosidyadic_god]
Shrine to [Petty_god]
Shrine to [Cult_god]
Piles of refuse
Bubbling pits of {yellow|green|purple|brown|black|white|silver} goo
Rubble
Natural cavern^5
Weapon racks
Armor racks
Prison cells
Anodic generator
Cages
Tapestries
Curtains
Kitchen
Hydroponic gardens
Bubbling cauldrons of {tasty stew|green slime|water|ethereal smoke|pungent acid}
Partial cave-in
Dripping water
Puddles
Pools of blood
Coffins
Gargoyles
Printing press
Mushrooms ({glowing|poison|enormous|edible|pulsating})
Mosaics
Ready to collapse
Abyssal shaft
Partially flooded
Smithy
Medical beds
Operating room
Paintings
Abstract sculptures
Storeroom ({food|raw materials|junk|clothing|fuel})
Utility conduits
Faint music
Fake doors
Creeping vines
Dead [Monster]
Uneven floor
Mirrored walls
Lofty ceiling
Banquet tables
Windows to {a neighboring room|an extradimensional void|stone|mirrors}
Steam
[Weird_slogan] scrawled on wall
Unnatural {heat|cold}
Screens ({flickering|looping video|strange symbols|blank})
Adventurer corpses ({fresh|decayed|skeletal})^3
{Kobellin|Mycelian|Nylock} corpses ({fresh|decayed|skeletal})^3
Broken [Artefact]
[Treasure_container] containing [5-10000] fake besants
Trap: [Dungeon_trap]^15
[Dungeon_dressing] and [Dungeon_dressing]^40

>>Dungeon_trap
{Snake|Rat|Beetle|Scorpion|Spider|Crab|Centipede|Alien vermin|Worm} pit
Spike pit ({open|concealed})
Electified doorknobs
Fills with sand
Bear trap
Net trap
Poison dart
Gravity reversal plus ceiling spike pit
Explosive mine
Rolling sphere
Construct deployment ([1-4] HD, [8-2] AC, {Arbalest|Spear|Falchion|Hammer|Pistolet})
Auto-turret ({laser|napalm|bullets|bolts|sleep darts})
Quicksand
Slippery oil
Sticky goo
Magnetic wall
Poison gas stoppered by [Gem_with_val]
Poisonous mushroom spores
Flammable gas

Connections & Maps

In part 4b I wrote about how I laid out maps of entire dungeons. This helped me get a feel for size and the room-count/level relationship, but in a key I'm finding that generating one map per level is preferable.

for(lvl in unique(dungeon$nodes_df$level)){
  lvl_graph <- dungeon %>% select_nodes(level==lvl) %>% transform_to_subgraph_ws()
  export_graph(lvl_graph, file.path(mapdir, 'Dungeons', paste0(name, '_', lvl,'.png')), width=1400, height=1400, file_type = 'png')
}

To ensure I know where the stairs are, I incorporated room connections into each entry.

for (i in 1:nrow(key)){
  # connections
  roomcons <- cons %>%
    filter(from == i|to==i) %>%
    mutate(other_room = ifelse(from==i, to, from)) %>%
    mutate(text_con = paste0(other_room, ' (', rel, ')'))

  key[i, 'cons'] <- paste(roomcons$text_con, collapse=', ')
}

Compilation

I made a LaTeX macro for dungeon rooms, similar to the one I made for Hex contents:

\newcommand\room[5]{
    \small
    \textbf{#1} \textemdash \ %id
    \textit{#2}. %dressing
    {\color{carminered} #3} %monster
    {\color{goldenrod} #4} % treasure
    Connections: \textit{#5} % connections
}

And here's the code to concatenate the relevant bits into a dungeon key:

outfile <- file.path(mapdir, 'Dungeons', paste0(name, '.tex'))

cat(paste0('\\section{', name, '}\\label{',name,'}\n\n'),file=outfile,sep="\n")
cat(paste0('Origin: ', type, '\n\nLocation: ', hex_r, ';', hex_c),file=outfile,append = T)
cat('\n\n\\begin{multicols}{2}\n',file=outfile,append = T)

# loop levels
for (j in 1:max(key$level)){

  cat(paste0('\\subsection{Level ', j, '}\n\n'),file=outfile,append = T)
  cat(paste0('\\includegraphics[width=\\columnwidth]{Maps/Dungeons/', name, '_', j,'.png}\n\n'),file=outfile,append = T)

  # loop rooms
  for (i in pull(key[key$level==j, 'id'])){

    cat('\\room', file=outfile, append=T)
    bracketwrap(key[i, 'id'][[1]], outfile)  # id
    #bracketwrap(key[i, 'level'], outfile)  # level
    bracketwrap(key[i, 'dressing'][[1]], outfile)  # dressing
    bracketwrap(key[i, 'monster_assign'][[1]], outfile)  # monster
    bracketwrap(key[i, 'Treasure_desc'][[1]], outfile)  # treasure
    bracketwrap(key[i, 'cons'][[1]], outfile)  # connections

    cat('\n\n',file=outfile,append=T)
  }
}

cat('\\end{multicols}\n',file=outfile,append=T)

The dungeon is given a label in LaTeX so that I can reference the correct page number in the dungeon's hex.

The Result

The dungeon generated for hex 269-269 has 104 rooms.

Here's an example page from the key:

Note that 'C' means 'corridor', 'D' means stuck door, 'L' means locked door. 'Obstr.', 'Trap', and 'Open' should be self-explanatory.

Initial observations:

Tying it Together

I rolled 'Castle' as the origin type of this dungeon, so I'm going to call it Murdicog's Manse, named for a Cyberian warlord of yore who settled here after pillaging the red hills of Mangala.

Since I over-weighted the dead body entries in the room dressing table, I'm going to say that the dead adventurers, kobellins, mycelians, and nylocks were the result of a relatively recent failed attempt at closing off the dungeon's Mordengard connection (more on that later).

In room 21 there's a logic engine mainframe and a hedge wizard, so I added:

The wizard's name is Euphonia Mandelbrot. She has been attempting to get the logic engine working again, as she believes it has a grimoire stored in memory. The Archimage in room 71 knows the login password.

I figure Euphonia could be a potential hireling, or replacement PC, or I could stash a MacGuffin in the logic engine's memory banks.

Room 23 has 'Trap: Flammable gas and Infirmary and Kobellin corpses', so I added:

Corpses are scorched and barely recognizable as kobellins. A thin layer of carbon rests on the smooth steel surfaces of the infirmary room. Highly flammable fumes leak out from poorly-sealed vats of disinfectant, igniting when any open flames are brought fully into the room.

There's a warlord in room 30 and 15 landsquenets in room 32, so I added:

Darlag the Defiler fled here with his pod of treasure after Landsquenets raided his camp. A contingent of his pursuers wait in room 32. He is well armed with four loaded pistols and a two-handed sword.

and

The landsquenets chased the warlord in room 30 into the dungeon, but lost track of him. The bubbling cauldrons contain the mushoom stew they have been eating for the last several weeks. They will offer 5% of Darlag's treasure to anyone who helps them attack, but will requisition his armor.

In a room on level 5 where three Cyberians exist in a room with 1200 gold:

The Cyberians have been playing a game of Nomic for the last 336 years; the canister contains the betting pool. Players may ante up if they wish.

I won't belabor this, the point is that so far I've found the random generator's results to be conducive to extrapolation.

Conclusions

Is this a good dungeon? One that's fun to run? I don't know yet. I can say that I've had fun fleshing out some of the entries & feel like it has at least reached a level where I could run a passable session with no extra prep.


  1. These dungeons aren't meant to be finished -- I'd rather they be nearly impossible to clear, thus remaining a perpetual potential source of chaos.

#Antibor #DIY #dungeons #lore24 #random-tables