Statblock Generator
I am trying to understand my “relationship” with generative AI, as I’m sure a lot of people are. It’s not good at everything. Promises are being made that will never be realized, about how this will be some silver bullet—an every-tool. I believe that there will be great consequences when the music stops and reality comes crashing down. I believe that it is being used recklessly and without regulation in personal, professional, and governmental contexts. This is to say nothing of the social implications. All of this I believe, and I believe it is an amazing tool that can result in amazing good for the world. I’m coming to find it’s another tool in the toolbox. It’s a very powerful tool, to be sure, like going from a hand drill to a power drill, but a tool nonetheless. Just like how the internet gave us tutorials, forums, etc. to answer every question or troubleshoot every problem, AI has taken the next step in reducing the cognitive load required to problem solve certain tasks. Now more than ever, we must guard our minds against cognitive deloading.
I talked about generative AI in learning and research here, and I’m hesitant to say any more because my opinion on AI evolves daily. Besides, the point of this post is to discuss a recent foray into AI and explain an interesting use case I found.
As stated above, generative AI is well-suited for some use cases, such as auto-completion, auto-formatting, file conversions, and spell and grammar checking. This I think is without question. Going through my ideas list, one I decided to play around with was an ARM (or OSRIC or AD&D or whatever) statblock generator. The basic idea is to have AI format monsters and NPC information into my condensed statblock format I use in my notes. It’s quite time-consuming, monotonous, and mentally draining to go through bestiaries and copy stats over every time I need to add a monster. Likewise to create yet another mid-level spell-user or mercenary NPC. The statblock format has also slightly changed over time, so being able to update old statblocks to the new format would also be nice.
Here’s an example input and output.
Input:
Here’s a statblock that’s incomplete and unorganized. Clean it up and organize it using Normal Mode
8th level elven thief named Amaril, S13 I12 W10 D18 C12 Ch15, wearing fur armour +1, 27 hit points, wields sky-wanderer blade, short bow, and dagger, has 1,403.5 gp, standard adventuring equipment, vanishing powder (1.5 uses), sky-wanderer blade +1. Female, 4'6", 54#, age unknown
Skill Output:
**Amaril**: Thief 8 (27 hp); AC 0 (*fur armour +1*); MV 120'; TH 16; AT short sword or short bow; D 1d8+1 (*sky-wanderer +1*) or 1d6 (short bow); SA thief skills (CL96 HI69 LI30 TR65 MS77 PL77 PP80 RL45 RS30); SZ M (4'6", 54#, age unknown); AL !!; S13 I12 W10 D18 (-4) C11 Ch15 (+15%); SV D12 P11 R12 B15 S13; XP !!/!!
- **Equipment**: *fur armour +1*, *short sword*, *sky-wanderer blade*, short bow, dagger, long spear
- **Wealth**: 1,403.5 gp, *vanishing powder (1.5 uses)*
- **Special abilities** (elf): +1 to hit with sword and bow; twilight vision 60'; 1-in-6 chance to notice secret doors, 2-in-6 when searching, 3-in-6 for concealed doors when searching; 4-in-6 chance to surprise when wearing non-metal armour and (or >90' in advance of party), drops to 2-in-6 if a door must be opened.
- **Special defenses** (elf): 90% resistance to sleep and charm, ageless
- **Thief skills**: climb 96%, hide 69%, listen 30%, manipulate traps 65%, move silently 77%, pick locks 77%, pick pockets 80%, read languages 45%, read scrolls 30%, backstab (x3 damage multiplier)
- **Background**: !!
- **Personality**: !!
- **Appearance**: Female, elf, 4'6", 54#, age unknown
The reason I like this idea is as follows. First, it’s a very narrow and well-defined problem. Format already existing information into a well-defined and unchanging format. Second, it’s not a creative task. I don’t like the idea of passing creative authority over to AI in running my own game. The creative expression and storytelling with my friends is the fun part. If I give that up, why even run a game? Third, using AI to make an elf game app is hardly an egregious moral act.
So I did it. I learned how to use Claude Skills (and the difference between Skills, Agents, Sub-Agents, MCPs, and Tools) and made the thing. Let’s go through some of it and identify some takeaways (in bold).
My first observation is that it is actually quite involved. There’s the main SKILL.md file, which is currently 486 lines. There are also two short Python scripts, thirteen Markdown references files, and five JSON reference files. I didn’t expect it to be so difficult to make something as simple as an accurate statblock generator, but it turns out AI is both very smart yet also very stupid. Like any human being or computer, you need to give it clear and specific instructions. Unlike normal programs or scripts, however (but very much like humans), just because your instructions are clear and specific doesn’t mean they will be followed. You have to use some tricks to get what you want, and even then it’s not always perfect.
For example, no matter how many times I told it not to infer details about a statblock, it would always go ahead and hallucinate monster abilities that don’t exist. 20+ versions of “DO NOT INFER” throughout the skill had little effect. (It always wanted to include a “poison spore” ability for some reason.) To fix this, I created “Operational Modes” at the top. The AI then has to choose which mode to operate in and cannot deviate. This seemed to fix the issue, though it now requires you to define the mode in the prompt. I tried to set the default mode to strict, but it always seemed to think “Normal mode” was the default mode (which would be a fair assumption if I didn’t have “Strict Mode (Default)” as the first mode header).
My second observation is that it somehow has capabilities beyond what I encoded. I designed the skill to take an incomplete or different format statblock and standardize it. If you gave a monster name and put it in completion mode, it could also reference a database of monsters and attempt to find a match. What I never expected is that you can describe wanting a monster based off nothing but a rough description and it would return a very close match of what you’re looking for. To give a specific example, here’s one test I ran and its output:
Input:
find the closest monster you can for adnd in normal mode that is tall, lanky, and really unsettling, with about 8-12 HD, and not undead. it should have animalistic traits, as well.
After the usual AI filler text, here’s the main output:
The Squealer is the clear winner — 8–9’ tall, three-armed (grotesque and unsettling), animalistic (piggish face, claws, fur, predatory ambush hunter), 10 HD, non-undead. Let me calculate HP and build the statblock.
Reference check completed. I searched monsters-1e.json, monsters-osric.json, and monsters-2e-core.json in priority order per your skill’s monster-sources.md.
Best match: the Squealer (found in monsters-2e-core.json).
Here’s the statblock in Normal Mode — values sourced directly from the 2e entry, translated to your 1e revised format. I noted where I had to rely on the 2e data.
Squealer: NA 1d4; HD 10 (45 hp); AC 4; MV 90' (150' climb); TH 10; AT claw/claw/claw/bite or drop; D 1d6+6/1d4+1/1d4+1/1d4+1; SA drop (from above, all 4 attacks), hug (if 2+ claw hits, rear claws rake for 1d4+1 each), voice mimicry; SD camouflage (-2 to opponent surprise rolls); SZ L (8–9' tall); Int Low (5); AL N; SV D8 P9 R10 B9 S12; TT !!; XP !!
- Voice Mimicry: The squealer can imitate wounded animals, humanoid screams, and infant cries to lure prey into ambush positions.
- Camouflage: Its mottled green-brown fur coat blends into forest and jungle canopy, imposing a –2 penalty to opponents' surprise rolls.
- Drop: When attacking from above, the squealer lands on a target and delivers all four claw attacks simultaneously.
- Hug/Rear Rakes: If two or more claw attacks hit, the squealer clamps on and its rear legs rake for 1d4+1 each (same round).
- Habitat/Society: Solitary or small groups of 1–4. Inhabits temperate forests and tropical jungles, uses its third dorsal arm and upper canopy to ambush from height.
- Ecology: A carnivorous apex ambush predator. Its three arms — two forward, one sprouting from its back — and grotesque piggish visage make it deeply unsettling on sight.
Notes:
- THAC0 (10), saves, and HP calculated from your skill's tables for HD 10.
- AC 4, movement, attack routine, and damage pulled directly from the 2e entry.
- TT and XP marked !! — not found in the 2e entry and not present in monsters-1e.json or monsters-osric.json for this creature. Do you want to assign those, or should I estimate from comparable 10 HD monsters?
- The Squealer's Int score of 5 (Low) puts it below the detect invisibility threshold at HD 10, so no IL% was added.
At first, I was dumbstruck by this outcome. I did three more tests and this behavior seemed consistent. On one hand, this moves into the territory of “AI making decisions for you”, but on the other hand it can search the thousands of monsters available and find a match based on your creative desire and description. What a deal!
You may already be thinking: is the output correct? This is where the issues began. Once I settled down and started checking its work, I found issues. The drop attack actually does 5d4 damage, not “four claw attacks simultaneously”. This bit came from the monster description being misinterpreted. The hug/rake attack is also off. Per the AD&D description:
If the squealer hits with both its other arms, it pulls the prey into a hug, then bites while raking with its rear claws. The hug causes 2d4 points of damage per round the prey is held. A victim being held or hugged loses all Dexterity bonuses to Armor Class; held prey receives a -2 penalty to attack rolls, while a hugged victim is unable to attack unless already holding a small weapon. Held or hugged prey must make a successful bend bars roll in order to break free.
It also omits two very helpful bits of advice for running the squealer:
One of the squealer’s favorite tactics is to take prey high into the trees and then drop them to the forest floor.
If a squealer is not especially hungry when it catches prey, it may attempt to knock or throttle its victim unconscious, then secure it to a tree trunk with vines.
This seems essential advice for running the squealer. The second one especially is only one line but can spawn a whole adventure of complications: the squealer defeats the party, but rather than a TPK the GM narrates the party waking up hanging upside down in vines. Or perhaps the squealer steals away one unconscious member and the rest must set out to rescue them before they are eaten. All that is gone. Even for a condensed statblock, were I making it by hand, I would absolutely include these details. These judgment calls are what separate referee from AI.
This is a very good reminder to everyone that AI cannot be blindly trusted. It can hallucinate. It can misinterpret even the most straightforward of descriptions like, “Dropping on a victim requires an attack roll and causes 5d4 points of damage” into “When attacking from above, the squealer lands on a target and delivers all four claw attacks simultaneously.”
With all these errors in mind, the fact that you can give a large database of monsters and loose criteria for your desired monster and get an output of relevant suggestions is very helpful. That said, I would caution anyone using it this way to make sure, really sure, that you’re the one making the decisions when possible. Art (which your game is) is defined by the artist’s decisions. Why were there orcs there instead of goblins? Because you decided there should be. Take that away and what’s left? So while suggestions are fine for exploring options, make sure you’re the one in the driver’s seat, that the AI is only your assistant (emphasis on assist).
My third observation is more of a set of related observations. AI seems helpful for working with data. It took some HTML pages and converted them quickly and perfectly to JSON format, then could convert that to a new html file with my own custom format. It can make mass edits to data very quickly. It can use structured data as reference material. As someone with a software engineering background, I find this less impressive since most of this can be done with a well-written script, but the impressive part comes in its ability to quickly create a tailored script to your exact use case. For a natural language processor, though, AI seems only moderately effective at interpreting natural language text into structured and correct output. If you ask it to perform a subjective task like summarizing something (with some output requirements), it does a good job; if you give it unambiguous inputs and ask for an unambiguous output, it does a good job; if you give it natural language input and ask for an unambiguous output, the results are mixed, and the ways in which it fails aren’t always predictable. Human beings can make these mistakes as well, but that doesn’t mean it’s not worth considering.
The takeaway then goes back to the opening discussion of this post: AI is a tool. Could you use pliers to remove a nail? Sure, but it’s better to just use a hammer. Similarly, AI can help write code, but it should not be blindly trusted to write code, especially in a professional environment. The suggested tab-completion is an example of good implementation; you can read the suggestion, decide for yourself if it makes sense, then choose whether to tab complete or not. Agency is what matters: using it to assist your work seems like a good mindset. Current AI tools generally try to take away agency. (In fact, that’s a general trend of technology.)
I could get into every little detail about this skill, but I think I’ll leave it at that. I’ve attached the skill as a zip file below in its current state as of writing this.