The Great Antarctic Hexcrawl Pt. 3 - He Did The Mash (Random Monsters)
This is my own version of lore24, an admittedly over-ambitious attempt to procedurally generate a 128,000-hex crawl for my homebrewed far-future Antarctica, Antibor. Part 1 here. Part 2 here.
Before I populate Antibor with lairs and keyed dungeons, I need a list of monsters and foes. I've been adding piecemeal to a personal GM-binder bestiary for a while, but it needed some expansion and revision.
Antiborean monsters fall into a few categories:
- Classic D&D monsters, left pretty much intact but given silly product-identity-scrubbing names, like the Ocularch, Ochre Bulk, Lavender Jelly, and Mycelian.
- Re-imagined versions of classic monsters, like Kobellins and Elementals.
- Homages to the fiction that inspired Antibor, like the Alzabo (Wolfe) and Oast Rider (Vance).
- Weird shit I made up like the Devourer Palm and Idol Feaster. (Fire on The Velvet Horizon this is not, but I'm proud of a few of these.)
- Randomized monsters where I made up a name and let random generators do the rest. (See below)
The Monster Table
I'm keeping all the monsters and relevant stats in a .csv table. (See this post about inserting information from a csv into a LaTeX file). Since Archons & Armigers is OD&D-based, stats are written accordingly. Each monster has a column where a reference to a .tex file with additional description can be stored.
Aside from stats, the csv also has a OD&D-style no. appearing, no. in lair, and lair nearby columns, and a column for each biome storing the relative likelihood of that creature appearing as an integer. There are also three dungeon depth levels (Limnetic, Profundal, and Abyssal) that function the same way. These will be used to stock lairs and assemble encounter tables.
Generating Monsters
I'm finding that my creative process often begins with a catchy name that I then subject to perform a vibes-based extrapolation. (More random generators & GM tools should spit out evocative and ill-defined names rather than things). Jack Vance's Dying Earth series and the Appendix N Podcast episode on Cugel's Saga helped to crystalize this approach in my mind. Vance alludes to monsters like the 'Erb', 'Grue', 'Pelgrane', 'Deodand', and 'Leucomorph' without ever describing them in more detail than is necessary for the immediate situation; the effect is at once whimsical and sinister, naturalizing them as an ever-present threat that his characters are used to living with. I hope to capture a little bit of that feeling.
My list of made-up names is below. They're extremely silly, but (for me at least) they have a sense of personality that makes me want to discover their story. (Those italicized are homages in some way.)
- Ambulatory Diomatarl
- Bindrilisk
- Blerbit
- Bombulating Squink
- Carbuncle Drome
- Clavicorne
- Demihask
- Diatonga
- Felkrine
- Fusticule
- Goxipline
- Grue
- Hammedrine
- Hosticorn
- Krongu
- Krusp
- Lacerauk
- Leucomorph
- Lugubarb
- Morticarn
- Mosiplandaroid
- Mungle
- Nylock
- Rappagravit
- Rhizomatic Klingit
- Rubitark
- Silver Skrog
- Sorbitar
- Sospelline
- Strombolipede
- Thoul
- Tumbling Pobbit
- Yarb
- Yecht
- Yorp
- Yuvix Cloot
- Zutak
It's a long list, many will surely end up as cruft, but I'd rather go to big and downsize than introduce an arbitrary limit. The goal is to have a solid roster of common foes that can be richly developed when stocking the campaign, but also a diverse menagerie of ultra-rare monsters to keep players on their toes & add a sense of alien unknowability to the world.
Stats
I used R to quickly generate stats for the new monsters. HD was rolled randomly on a d12. AC on a d9. For speed I made a vector of options including fly and burrow speeds and just picked randomly. And for number appearing & no. in lair I had it select randomly from the list of entries recorded for other monsters. Biome preference levels were randomly drawn from (0,0,1,2,3). Some incongruous results were generated, but imo that's just another hook to extrapolate on.
Descriptions
I got hung up on this step because I have persnickety, exacting standards for how weird and alien I want my bestiary to be.
I initially had ambitious plans to write something like the demon generator in AD&D or the one-roll monster page in Worlds Without Number. But I decided these would overdetermine the monsters and stifle later creativity (and clutter up statblocks with extraneous formulaic text). I'd rather build up from an interesting prompt than pare down from a boring result.
So just as Vance was parsimonious with his monster descriptions, I opted to simply roll thrice on a table of adjectives I threw together one morning. This gives me a good starting point for a more detailed description if I ever get inspired later, and just enough to improvise with if I don't.
Monster Adjectives
- Putrescent
- Lumbering
- Nimble
- Glistening
- Alluring
- Segmented
- Luminous
- Anodic
- Voracious
- Blighted
- Corrosive
- Incandescent
- Vengeful
- Psychic
- Plumed
- Faceted
- Iridescent
- Prickly
- Garrulous
- Tormented
- Sadistic
- Mechanical
- Avaricious
- Blasphemous
- Reptilian
- Feline
- Ursine
- Canine
- Amorphous
- Anneloid
- Molluscoid
- Humanoid
- Avian
- Arthropoid
- Cunning
- Instinctive
- Wheeled
- Whirling
- Constricting
- Crushing
- Adhesive
- Insane
- Rational
- Mocking
- Inquisitive
- Elusive
- Stealthy
- Explosive
- Venomous
- Sorcerous
- Demonic
- Coiled
- Hirsute
- Methodical
- Necrotic
- Leathery
- Colorless
- Visceral
- Cybernetic
- Geometric
- Taurine
- Helical
- Chimerical
- Enthralling
- Humanoid
- Telekinetic
For example
The Ambulatory Diatomarl is 'vengeful, prickly, and ursine'. I'm imagining a crystalline hedgehog-bear that hunts down anyone who disturbs its (inevitably inconvenient) slumber.
The Goxipline is 'Molluscoid, Lumbering, Psychic' (and has 9 HD) so I'll say it's an elephant-sized (and I guess vaguely phallic?) land squid with psionic powers. I'm still working out what I want these to be; I think the ability to selectively edit itself out of others perceptions would be funny -- like, a giant elephant squid is rampaging through the village but nobody is able to integrate seeing it into their memories; chaos ensues, and adventurers are needed to devise some creative way to deduce its existence.
The Yarb is 'avaricious, plumed, instinctive', and 2 HD - perhaps a toothy little pterodactyl, that (driven mad by jealousy at its avian cousins) adorns itself with colorful scraps of cloth, paper, leaves etc. Acquiring something like a spell scroll would be a literal feather in its cap.
The current WIP version of my bestiary can be viewed here.
Code
library(tidyverse)
### Create placeholder
monsters <- read.csv(file.path(chapterdir, 'Bestiary.csv'))
for (i in 1:nrow(monsters)){
if (monsters$Description[i] == 'blank.tex'){
outfile <- file.path(chapterdir, 'Bestiary_desc', paste0(monsters$Name[i], '.tex'))
cat(' ', file=outfile, append=T)
monsters$Description[i] <- paste0(monsters$Name[i], '.tex')
}
if (monsters$r_desc[i] == 1){
## random HD
if(monsters$HD[i] == 0){
monsters$HD[i] <- sample(1:12, 1)
}
## random AC
if(monsters$Armor[i] == -5|is.na(monsters$Armor[i])){
monsters$Armor[i] <- sample(1:9, 1)
}
## random attack power
if(monsters$AADamage1[i] == ''){
monsters$AADamage1[i] <- sample(c('Heavy', 'Standard', 'Light'), 1)
}
## move
if(monsters$Move_in[i]==''){
monsters$Move_in[i] <- sample(c('3', '6', '9', '9', '9', '12', '12', '12', '12', '15', '15', '18', '9/18F', '6/21F', '12/21F', '9/6B'), 1)
}
## morale
if(monsters$ML[i]==''){
monsters$ML[i] <- sample(4:12, 1)
}
## n_appearing, n_lair
if(monsters$n_Appearing[i]==''){
# just pick an existing combo
roll <- sample(1:nrow(monsters[monsters$n_Appearing!='',]), 1)
monsters$n_Appearing[i] <- monsters[monsters$n_Appearing!='','n_Appearing'][roll]
monsters$n_Lair[i] <- monsters[monsters$n_Appearing!='','n_Lair'][roll]
}
## lair nearby
if(monsters$Lair_near[i]==''){
monsters$Lair_near[i] <- sample(c(1,2,3,4,5,6,7,8,9,10), 1)*5
}
if(monsters$n_Lair[i]=='n/a'){
monsters$Lair_near[i] <- 'n/a'
}
## treasure
if(monsters$Treasure[i]==''){
monsters$Treasure[i] <- sample(treasure_tables$Type, 1)
}
## biomes
biomelist <- c("Alpine", "Arid", "Savannah", "Chaparral", "Steppe", "Jungle", "Taiga", "Arratu", "Urban", "Necrozone", "Sea", "Limnetic", "Profundal", "Abyssal")
if (sum(as.integer(monsters[i,biomelist]))<1|sum(is.na(monsters[i,biomelist]))){
for (biome in biomelist){
if (biome=='Urban'){
monsters[i, biome] <- min(sample(0:1, 1), sample(0:1, 1), sample(0:1, 1))
} else {
monsters[i, biome] <- min(sample(0:3, 1), sample(0:3, 1))
}
}
}
}
}
write.csv(monsters, file.path(chapterdir, 'Bestiary.csv'))
############################ monster generation (description)
for (i in 1:nrow(monsters)){
if (monsters$r_desc[i] == 1){
outfile <- file.path(chapterdir, 'Bestiary_desc', paste0(monsters$Name[i], '.tex'))
cat('\n', file=outfile, append=T)
if (grepl("^\\s*$", read_lines(file.path(chapterdir, 'Bestiary_desc', paste0(monsters$Name[i], '.tex')))[1])){
outfile <- file.path(chapterdir, 'Bestiary_desc', paste0(monsters$Name[i], '.tex'))
monst_desc <- r_gen_eval('[Monster_spark], [Monster_spark], [Monster_spark]')
cat(monst_desc, file=outfile, append=T)
}
}
}
Leave a comment on Reddit