Reification
It’s been a while since I posted something here, but that’s not because I haven’t been hard at work! I made some solid progress over the three day weekend, including a huge refactor of how items and places work in the game, largely due to a discovery about how I’m using the LLM that changed some of my thinking.
Mechanics vs. Narrative
I posted a while back about the problem of the Glimmerwings - a case where the LLM hallucinated an enemy type that did not exist in the game. There were several problems highlighted in that post that I have grappled with time and time again. The main one that constantly seems to haunt me is asking the LLM to do too much in a single prompt. Every time I think I’ve minimized how much I’m asking it to do I discover that no, it could be further broken down.
In that post, I had broken down my prompt for creating quests into three passes:
- Generate broad stroke narrative goals with no specifically named details. IE: attack an enemy, not attack the Glimmerwings
- Map the narrative goals to existing mechanics. This is where we determine that the quest is
attackand not one of the other options. - Expand the player-facing narrative text with the mechanical details in mind. Now that we know it’s an
attackquest, please pick from this list of known enemy types what it is we have to attack.
I thought at the time the issue was that I had tried to do all three in one pass, thus allowing the LLM to hallucinate “Glimmerwings”, an enemy type I had neither stats nor art for. My choice was either to figure out how to let the LLM generate all of that (difficult), or force it to instead pick enemy types from a list (easy).
However, I was missing an important piece of the puzzle.
The LLM Isn’t the Only One Who Hallucinates
In the very beginning of the game, I ask the player to enter “motivation” text - specific goals, past history, etc. My theory is that unless we allow free-form text input from the player, the magic of talking to an AI is lost.
Think of it this way – if I wrote a game that made a perfect Baldur’s Gate 3 clone with dynamic content genrated on the fly, but the only input the player has is selecting things from pre-existing lists (like navigating dialogue trees), can the player even tell that there’s an AI involved? If they can’t, what is the actual value of using an AI rather than hand-authoring everything?
I think that by letting the player enter arbitrary text like “I seek the hidden idol of the Blood God” and then see that manifest in game content, that is where the magic of AI becomes apparent. Thus the title of this section - the player also hallucinates and we have to figure out how to handle that.
Creating Content From Raw Text
Consider the player motivation: “I carry a letter addressed to a woman named Elara.” This is an actual example from one of my sample motivations that the game will give you as a starting point if you don’t want to write your own. If this is in your motivations, then you probably want there to be an NPC in the game somewhere named “Elara”. Also, it would be nice to have a letter addressed to her in your inventory, no?
This problem isn’t terribly different from the Glimmerwing problem – whether it comes from the LLM or the player, there will be cases where I have a block of text from which I need to extract people, places, or objects that should exist in the world. The only unique thing about the Glimmwerwing case was that enemy types are about the most complex piece of data in the game - they have stats, animations, etc.
When it comes to items or places though, creating in-game content from raw text is actually not that hard. A quest item (not equipment, but a macguffin) is just a name, description, and an icon. The first two are pure narrative text, the stuff the LLM is pretty good at inventing, and the icon can certainly be picked from a list. Likewise, a place in the world is just a hex or group of hexes on the map with a name and description. Again, the LLM can make up the narrative text and then specify what terrain and/or feature types that should represent and we can go find an appropriate one on the map pragmatically.
Reification
The AI taught me a new word: reify:
To make an abstract idea real or concrete.
Once I realized I had to solve this for player input text, why not use the same solution for LLM generated text? What I came up with is the reification service. This system does the following sequence:
- Ask the LLM to extract specific entities from an arbitrary block of text. For each list the name, description, and type (one of
person,place, orobject). - Present the LLM with the list of pre-existing things of the appropriate type to see if it can map it to an existing one already in the game.
- If that fails, create a new thing and ask the LLM to pick the required detailed data from existing lists (IE what type of hex for a place, what icon for an item, etc.)
Step 3 gets much harder for more detailed data. Surprisingly, I actually had already solved this for NPCs - the LLM can construct sprites out of the same layering system we use for player sprites that was required to handle equipment (assuming NPCs are all human). So the only data type this is actually difficult for is enemies, which at this point I’m simply not handling.
This refactor has actually simplified a surprising number of things. At one point I had three types of items: inventory items for the player’s equipment, quest items generated on the fly to server as quest macguffins, and “legendary” items that were created by the LLM for longer ranging motivation support. Now items are items - some are hand-authored and others created on the fly by the reification service.
Problems for the Future
Ultimately, I have set myself up to be right back where I started. How would I handle a player motivation like “Kill all the Glimmerwings in the forest”? But the fact is, this problem was lurking there all the time. I suppose I’m going to have to figure it out eventually.
I’m going to let that one sit for a while. For now, I’m focusing on just making the quest loop feel good. The reification service is setting me up nicely for tying player created things via their motivations into the quest generation, which is really nice. But also causing a ton of edge case problems that I’ve got to work through.
Onward!