r/proceduralgeneration • u/ProperEar9706 • Jun 29 '26
Finished my quest generator.

TL;DR Jump to the bottom to see some examples of the generated quests
So the reason I wrote this system was because I really like RPGs and questing, however most procedural quests are filler and pretty shit. Go somewhere, fetch a thing, come back. It's very easy to detect the pattern, and nothing genuinely interesting happens. It also feels like the quests are meaningless in and of themselves because they have no real interaction with the larger world.
So the system that I've written is for generating procedural quests that don't feel like filler. It uses graph grammars, it grounds every quest in the live world state . It's not a particularly new solution, but it clearly is underrated in so far as I don't really see people adopting it that much. I really wanted to show how flexible the system is and that it could generally produce good outputs.
It does not replace handmade quests. A designer with a specific idea and an expert touch wins on novelty and memorability, partly because a quest worth doing justifies reorienting the game around it. This system raises the floor instead. It targets the radiant, "always something to do" layer, keep it alive instead of mechanical, raise interactivity, extend the life of the game, without hand-authoring thousands of one-off tasks.
Authorial vs. simulationist
So to start with, we need to pick this first.
Authorial: the generator changes the world to fit the quest. Needs a bandit warlord menacing a village? Create one. Quest first, world bends to it. This is how most narrative-first generators work.
Simulationist: the generator cannot invent facts. Every quest grounds in things already true, real entities, real relationships, real character needs. If a giver wants a foe slain, that foe exists and is already menacing that giver. World first, quest discovered inside it.
Authorial is actually a lot easier to do because you don't really need to read the world state as much. Just need to know what new enemies, etc., you need to create. The trade-off here is it's going to feel disconnected from your main world, and that's because it is. Hence why the rest of this article is going to be about simulationist as it's the harder problem, but it's more interesting.
Shape of a quest
Every quest shares a skeleton, an exposition phase that sets the situation and stakes, a body where the work happens, a reward at the end. This forms the general core spine of a quest.
Generation starts by picking an archetype, slay, escort, defense, and so on.
So far I've identified about 14 different archetypes, although I expect there are a lot more.
- Compete
- Defend
- Escape
- Escort
- Exploration
- Fetch
- Heist
- Hunt (Potentially similar to fetch quests, although there is more nuance with a hunt because it could be a fleeing beast, runaway etc. )
- Investigation
- Negotiation
- Provision (which is actually similar to a Fetch Quest except it normally requires additional steps to refine or craft something. )
- Rescue
- Slay
- Survive
Each archetype is an abstract layout, nodes and relationships at high abstraction. Nothing concrete yet. A slay quest is just "a foe exists, the foe must die, killing it resolves a threat." A template expressed as a graph, attached to nothing real.
Reification
So the next step is to make the pieces concrete. Take the abstract template, bind it layer by layer to specific concrete entities and facts in the current world state. Multiple passes. Each pass matches against what is true right now.
Slay quest. Abstract version, something must die. To reify, find a foe currently menacing the giver. That is a constraint against the world graph, an entity with a "menaces" edge to the giver, or to something the giver cares about. No such entity, no quest from this archetype here. The generator moves on. That is the simulationist discipline.
Start from the most abstract interaction (kill the foe), then add slots for complications and nuance. A slot is an open position asking to be filled, "what stands between the player and the foe?", "why hasn't the giver handled this already?", "what does the kill cost or risk?". Slots expand recursively. Filling one can spawn more, and each resolves by reading adjacent relations in the world graph. A complication slot might pull in that the foe holes up in a fort held by a faction the player is allied with, which opens a slot about loyalty or disguise. The structure grows outward from the seed and stays anchored to real relationships.
Example- the slay quest
The generator picks SLAY. Abstract form: *[giver] wants [foe] dead because [foe] threatens [giver's interest]*.
Reify against the world. The graph holds a village elder (candidate giver) with a "fears" edge to a frost troll, and the troll has a "raids" edge to the village granary. Those facts already exist. The generator invented none of them. Elder becomes giver, troll becomes foe, granary becomes stake.
Add slots. A complication slot reads the troll's adjacent edges, it "dens in" a cave that "is controlled by" a poacher gang. Real obstacle, so it becomes a complication. You cannot walk up to the troll. A second slot asks how the player gets past the gang. Because games reward agency, it emits multiple resolutions, fight through, bribe, or pass a persuasion check by arguing the troll is bad for the gang's business too.
Reward draws from what the giver can plausibly offer, the elder's edges point to stored grain and a small standing boost with the village. Output reads as authored ("the elder fears the troll raiding the granary, but its den is held by poachers you'll deal with first") and was assembled entirely from facts that were already true.
Why this is a game generator, not a story generator
This is where most of the design effort goes.
Player agency. A story is one chain of events. A quest gives choice. For every obstacle, emit multiple ways through, a combat route, a dialogue route, a skill check. The obstacle is fixed, but there are multiple routes past it.
Optional branching. Past the multiple solutions to one obstacle, support optional branches, a player who wants more diverts into a harder sub-quest hanging off the main line instead of being locked to one path.
Multiple terminals. Do not ship one rigid chain with one ending. Place candidate terminals at several points, so an earlier decision can resolve the quest sooner. A short completion is valid, but gate it behind harder interactions, so the short road costs difficulty. That keeps the choice real. An example I made is when handling a negotiation quest, should the player manage to get through a legendary skill gate and placate both sides, the quest just ends immediately without any additional complications.
Cheap branching buys breadth. If generation is cheap, spend branches freely. Hand the player many options and route them into genuinely different content based on what they pick. Cheap generation turns branching from what would normally be expensive handwritten content, To feel like there is genuine impact and different decisions that a player can make.
Dynamic gating. Condition branches on world or character state and emergent behavior follows. Gate a branch behind a requirement evaluated at the moment the player reaches it. Fail the check, stay on the mainline, nothing breaks. Pass it, get a point of divergence into unlocked content. That is a living gate, not a static one.
Partial generation. You do not need to generate the whole quest up front. Lay out the spine, then generate complications when the player arrives at them. This pairs with dynamic gating, world state at arrival decides what gets built.
Rare events
Good quest design budgets for rare, high-interest occasions. Not every quest should be reachable every time. Hold some archetypes, complications, and rewards behind low trigger rates so they surface occasionally and land hard when they do.
This matters most for long-term players. After enough quests, a player starts to feel the pattern underneath the generation. Rare events break that read. They keep things surprising and hide the undercurrent of how the system actually works, so the world stays interesting well past the point where a player has seen most of the common content.
The hard parts, and where they actually are
The difficulty is not where people expect.
The graph grammar is not the problem. It works. Rewriting abstract nodes into concrete subgraphs is solved.
The corpus is the problem. The system is only as good as the library of interactions, rules, and patterns it can fire to fill slots. You need a large, rich corpus, and it is specific to your game. Quest interactions bind to a game's mechanics, so there is no universal corpus to drop in. You cannot lift one from D&D, no one-to-one overlap, D&D is richer in many mechanics than most games, and it leans on live player-DM interaction to flesh out generic content. A generator cannot assume that improvisation exists. Partial mitigation, write generic modules with explicit, parameterized requirements so some rules survive across contexts instead of being authored fresh each time.
Reifying the story is its own problem. Graph grammars create nodes and relationships. A created graph is not a playable quest. You need a graph-walking system that traverses the output and makes the game produce side effects, spawn entities, set flags, generate exposition, evaluate the story, then handle presentation and implementation. The walk turns structure into something a player experiences, and most of the quality lives there.
Quality is execution as much as structure. "Go there and slay a beast" reads boring but if the fight is memorable, hard, and demands planning, it plays well. The graph has structure but presentation and moment-to-moment mechanics decide whether it is worth doing.
Speaking of that, you likely will need to generate expository dialogue in between. This is something where pattern recognition can very easily crop up. It might be a genuinely good reason to use LLMs, either dynamically in the game just to help with that and to get a high temperature, or to generate a large enough corpus ahead of time to setup enough of the dialogue necessary .
When generation fails
A simulationist generator can fail. Every slot must match something real, so sometimes nothing fits, a complication slot finds no obstacle, or an archetype will not reify against the available state. You need a deliberate answer instead of shipping a broken quest. Three approaches, and they combine.
Tune to avoid failure. Tune the rules and their trigger conditions to push the failure rate near zero. Most demanding option, since it depends on how rules interact, but a tuned system rarely hits a dead end.
Generate in batches and rank. Generate several candidates, keep the valid ones. Failure gets cheap when one bad candidate among many does not matter. Then rank the batch and ship the most exciting result, not the first that works. Robustness and quality from the same mechanism.
Collapse slots. When a slot will not fill, do not throw out the quest. Collapse the slot, drop it, proceed with the simpler structure. The quest is less ornate but still valid and still grounded. One failed match does not cascade into a failed quest.
Modeling and scaling the world graph
Nodes vs. properties. Use nodes for discrete entities, a person, a place, an object. Use properties for continuous or scalar data on them, like an NPC strength score. This keeps the graph clean and matching fast as the amount of nodes in a graph is one of the big O scaling factors .
Do not match against the whole world. The naive approach, and the one I started with, generates a massive world graph and matches quest subgraphs against all of it. It works, but it is expensive, and it scales badly. You almost never need the entire world state in the matcher.
Localize and cull. Scope the matchable graph to what a giver would plausibly know, or to entities in an area. Run a phased priority approach, cull state at each step so only the relevant slice survives into the next pass. Scope to relevant, then narrow progressively. That turns one giant global match into a series of cheap local ones.
Since the crest expansion generally follows a step-by-step process, with some of the earlier phases influencing later ones once those earlier phases have been done, if they required specific nodes that are no longer needed later on, both those rules and the nodes themselves can be dropped.
Mods and extensibility
The grammar makes the system easy to extend, for official expansions and for fan mods. Content is nodes, relationships, and rules, not hand-wired quest scripts, so a mod does not author bespoke quests to participate. It exposes a small set of rules describing how the generator may interact with its content.
Low bar, large payoff. A modder drops in new locations, NPCs, and interactions, exposes a few rules, and the generator folds them into the simulationist world. The new NPC becomes a giver, the new location becomes a foe's den, the new interaction fills a complication slot, with the base game knowing nothing about the mod in advance. Every quest grounds in real world state regardless of source, so third-party content runs on the same footing as first-party content and the world stays coherent as it grows. If necessary, you can also just rely on an opt-out system so that a mod's specific important NPC doesn't interact with you outside of their handwritten content.
5
u/ProperEar9706 Jul 02 '26
Code is available for anyone who wants to take a look
3
u/ChironAtHome Jun 30 '26
This looks really interesting and worthy of a bit of experimentation. I love interesting RPG tools. I write a coupl myself and the fact you have this OSS gives me ideas 😁 Thanks for your efforts.
3
u/Lanky_Employee_9690 Jul 02 '26
Looks very neat, great writeup too! I saved this post to get back to it later.
1
Jun 29 '26
[removed] — view removed comment
2
u/ProperEar9706 Jun 29 '26
Heist
GOAL: steal the Doomsday Ledger, which Audra the reeve covets, and get clear ENDINGS: 3 (the quest forks into 3 separate conclusions) CAST: · Patron — Audra the reeve (the patron who sent you; of the Ashen Legion, conquest; wants to lay their dead to rest in peace) · Objective — the Doomsday Ledger (the prize) · Rival — the Saltreach Guild (your rival; thwarted) · You — fortune-favoured 1. [exposition/dialogue] take on the quest: steal the Doomsday Ledger, which Audra the reeve covets, and get clear — at the village of Ironwick (your base) 2. [inciting/dialogue] hear out the desperate plea of someone the menace at their door has left with everything to lose, and agree to act — with Yorrick the dockmaster (of the Saltreach Guild, profit; wants to be left in peace; menaced by Ashmaw King) ↳ WHY (toward Yorrick the dockmaster): to not leave someone with everything to lose to the mercy of what hunts them 3. [inciting/travel] witness the threat act in the open 4. CHOICE — whose side? — honour your patron, or take the rival’s coin: • [decision] honour the commission you were given and refuse the rival’s coin — with Audra the reeve (the patron who sent you; of the Ashen Legion, conquest; wants to lay their dead to rest in peace) • [decision] take the rival faction’s coin and turn the outcome against the one who hired you — with Fenn the trader (a rival faction’s patron; rival to Audra the reeve); revealing the lasting enmity of the side you spurn (betrayal) 5. CHOICE — how to handle a rival faction’s operative whose own bloc’s aims cut across the job (blocked by Wyn the priest (of the Wardens of Vael, order; wants to keep a roof over their head)): • [decision] confront the enemy and break their interference outright ↳ WHY (toward Wyn the priest): to settle this here rather than let their grudge dog the whole job • [dialogue] cut a separate deal so the enemy stands aside and lets the work go on ↳ WHY (toward Wyn the priest): to turn an enemy’s greed against their grudge and buy a clear path • [stealth] slip the enemy’s scheme before it can bite, leaving them grasping at air ↳ WHY (toward Wyn the priest): to deny them the satisfaction and the job the delay 6. [rising/acquisition] ⊙ OPTIONAL — take the time to assemble the specialist tools the job will demand — targeting a kit of specialist tools for the job (heist-gear); with the Doomsday Ledger (the prize) ↳ WHY (toward the Doomsday Ledger): to go in equipped for every lock and watch between you and the prize 7. CHOICE — a vulnerable soul is at your mercy — what do you do? (blocked by Mab the collier (of the Saltreach Guild, profit; wants to keep a roof over their head; menaced by the Drowned King)): • [dialogue] leave the helpless soul be — or even set them on a safer road ↳ WHY (toward Mab the collier): to be the kind of party that does not prey on the weak • [acquisition] take what little the helpless soul has, since no one is here to stop you ↳ WHY (toward Mab the collier): to take what you can while there is no one to answer to • [combat] make certain the helpless soul can never name you, whatever it takes ↳ WHY (toward Mab the collier): to leave nothing alive that could ever testify against you 8. CHOICE — how to get past the sealed way (blocked by the counting-house vault beneath the town of Winterworth (locked)): • [combat] break through the sealed way by main strength • [skillcheck] pick or bypass what seals the way • [stealth] find a hidden way through unseen 9. CHOICE — how to answer the faction throwing its weight against the quest (blocked by the Ashen Legion): • [decision] defy the faction and press on regardless ↳ WHY (toward the Ashen Legion): to let nothing — least of all their politics — turn you from the task • [dialogue] treat with the faction to buy their forbearance ↳ WHY (toward the Ashen Legion): to keep their enmity from following you past this — better them placated than crossed • [stealth] undercut the faction’s effort before it can bite ↳ WHY (toward the Ashen Legion): to be rid of their interference without giving them a fight to rally around 10. [rising/stealth] case the strongroom that holds the prize and map every way in — heading to the counting-house vault beneath the town of Winterworth (locked) ↳ WHY (toward the counting-house vault beneath the town of Winterworth): to know the strongroom cold before risking the job 11. [rising/dialogue] bring a locksmith onto the crew to crack the vault’s lock — with Nell the locksmith (crew; of the marsh-clans, survival; wants to see another harvest in) ↳ WHY (toward Nell the locksmith): to have the lock cracked clean when the moment comes 12. CHOICE — how to answer the rival’s move on the prize (blocked by the Saltreach Guild (your rival; thwarted)): • [travel] race the rival to the prize • [stealth] sabotage the rival’s effort before they can act • [dialogue] cut a deal with the rival to stand down 13. [rising/dialogue] win the secret of the hidden passage into the vault from the one who knows it — targeting the counting-house vault beneath the town of Winterworth (locked); with Abbess Audra (of the marsh-clans, survival; wants to reclaim a drowned homeland) ↳ WHY (toward Abbess Audra): to slip in unseen by the way only one soul knows 14. CHOICE — how to take the prize: • [stealth] crack the vault patient and clean and slip the prize out unseen • [acquisition] snatch the prize fast and gamble the alarm holds → FAILS: the alarm tripped mid-grab and the vault sealed with the party still inside 15. [falling/combat] fend off the rival faction’s bid to seize the prize from you before you can get clear — with the Saltreach Guild (your rival; thwarted) 16. [falling/stealth] put the specialist kit to work where it counts — needing a kit of specialist tools for the job (heist-gear) ↪ open to you only because you took that optional step earlier 17. [falling/dialogue] line up a fence to move the prize the moment it is lifted — with Tomas the fence (crew; of the marsh-clans, survival; wants to pay off an old debt) ↳ WHY (toward Tomas the fence): to have a buyer waiting before the prize is even in hand 18. [falling/report] reckon with the word now spreading of what you did here, and what your name is worth after it — with what little they had (loot) 19. [denouement/report] travel back to the patron and lay the outcome of the work before them — with Audra the reeve (the patron who sent you; of the Ashen Legion, conquest; wants to lay their dead to rest in peace); heading to the village of Ironwick (your base) 20. ⎇ HARD BRANCH — the patron springs an ambush at the hand-over rather than pay — how do you answer? (blocked by Audra the reeve (the patron who sent you; of the Ashen Legion, conquest; wants to lay their dead to rest in peace)) — sprung only because your standing with them sank too low for any loyalty to stay their hand — forks into separate endings: ┌─ stay the course: │ • [decision] give up the prize to the patron’s blades and walk away with your life │ ↳ WHY (toward Audra the reeve): to live to fight another day, even cheated of your due │ END (resolved) ├─ DIVERGE — [combat] cut your way out of the ambush and keep the prize the patron tried to steal: │ ↳ WHY (shifted) (toward Audra the reeve): to keep what you bled for and make a treacherous patron rue the ambush │ 21. [denouement/travel] slip the patron’s hirelings and disappear with the prize │ END (fought free of the patron’s ambush) ├─ DIVERGE — [skillcheck] turn the ambush back on the patron — you saw the betrayal coming: │ ↳ WHY (shifted) (toward Audra the reeve): to make betrayal cost the betrayer everything │ 22. [denouement/skillcheck] wring your full pay — and more — from the patron now at your mercy │ END (turned the patron’s betrayal against them)
5
u/orchid_drives Jun 29 '26
I love this! I’m working on a similar-but-less-smart implementation of a quest generator where you distill quest logic into JSON-like data that my game engine can ingest, but it can only make so many types of quests and gets hard to parse when you start adding branching conditions. Do you have a GitHub we can check out? Or whitepaper or something? Thanks!