Giter Club home page Giter Club logo

gm-trainer's Introduction

Here are descriptions of recent software projects I'm allowed to discuss (i.e. non-professional work.)

GM Trainer

GM Trainer is a sandbox environment for RPG Game Masters (GMs) to realistically practice spontaneous creativity. It uses LLMs to simulate human players' responses to the GM's descriptive narration, giving GMs a training ground to exercise critical skills like improvising descriptions, decisively answering player questions, and giving logical game-world responses to player actions.

screenshot

Master's Thesis: The Computer-Driven, Human-Controlled TTRPG

For my MSc research thesis, I researched, designed, and programmed ROLEPLAYINGGAME1, the first tabletop-RPG companion app to support runtime editing of game rules and content without stopping gameplay. My aims were to:

  1. Combine the flexibility of traditional RPGs with the complex, real-time processing of videogames by enabling game worlds and game rules to grow and change during use.
  2. Assess the viability of an all-in-one platform not only for playing and GMing RPGs, but also for designing them, because game designers' needs aren't met by existing apps.

ROLEPLAYINGGAME is a web application. To target the browser, I needed a way to evaluate game rules on the backend and frontend alike, for server-side validation and rule-sensitive UIs respectively. I avoided code duplication by implementing ROLEPLAYINGGAME in Clojure, which has production-grade compilers to both Java and JavaScript. This made >95% of my backend code portable to the frontend.

To efficiently make game state available to frontend clients, whenever a user action changed the game state, I sent a diff from the server to all clients. Having game state available on clients was necessary to keep information-rich UIs up to date. One of those UIs is shown below.

The GM's Inspector, with a command and one parameter specified.

The Inspector, part of the Game Master's UI, affords rapid, context-aware interaction with all game entities.

In this screenshot, a GM is using the Inspector: a context-sensitive menu for dispatching commands on in-game entities. For each command (like dislocate), the parameters for which the character Arvak can slot into (like target-entity) are dynamically discovered by introspection on Clojure functions. The GM can click any entity on any main UI screen to add it to the Inspector2.

Computational TTRPG Tools

My master's thesis grew out of my long-standing interest in implementing tabletop RPG systems in software. Before starting my MSc, I had already developed several Python tools for my own custom game system, including a pricing simulator for over 1,000 17th-century items, a program that generates characters' life stories based on their stats, and CLI tools for rapidly updating the game world during live gameplay.

One vendor from a market price table from my homemade RPG app.

One of the tables created by the pricing simulator.

The pricing simulator brings depth, granularity, and logic to an aspect of RPGs that has never progressed beyond numbers made up on the spot. As an example of my dedication, here's an explanation of how it works.

The simulator inputs are encyclopedia data on the relative abundance of raw materials at real-life cities. Every city "exports" some fraction of its resources everywhere else, using an all-pairs shortest path network. We then determine raw material prices for each city: the more abundant, the cheaper the unit price.

Tens of thousands of calculations specify how raw materials transform into purchasable tradegoods, specifying quantities like the length and radius of a spear haft, the thickness of a clay pot, and the amount of wood needed to build a half-timbered house. Each tradegood is defined by a "recipe," which I create by researching 17th-century manufacturing. A recipe consists of raw materials and other, simpler recipes, so the set of recipes forms a directed forest. Summing the prices of a recipe's components gives the tradegoods's final player-facing price3.

Ryan Quest

I made the text adventure Ryan Quest as a surprise birthday present for my best friend from college, Ryan Wright. The player controls Ryan in a parody of his real life. After doing all the writing, coding, and user testing, I flew out to surprise him with the game in person.

Ryan Quest was written in Inform 7, an unusual programming language which is laser-focused on being good for creating interactive fiction.

Footnotes

  1.  An acronym for RPG Operation, Learning, and Execution Platform Laden with Advantages for Yielding Infinitely Nitty-Gritty Games that Allow Malleable Evolution.

  2. For instance, the exploration hex grid (partially shown above) would let the GM operate on characters, items, and individual hexes just by clicking.

  3. This explanation glosses over some complexities relevant to game design, but not to engineering; I'd be happy to discuss my work (and yours!) in more detail by email.

gm-trainer's People

Contributors

maxwelljoslyn avatar

Watchers

 avatar

gm-trainer's Issues

Add max number of tries to exponential backoff for LLM request failures

I'm using a plain Exception rather than a more specific type because I don't know what errors exactly a third party library might throw upon a bad response. If I wanted to use their more specific library specific types, I would have to depend on them (e.g. to catch Claude errors, I'd have to depend on anthropic_py, or whatever Anthropic's Python package is called.) For now, I don't want to do that.

Work around Anthropic rate limits

According to the docs for Aider:

Anthropic has very low rate limits. You can access all the Anthropic models via OpenRouter without rate limits. For example: aider --model openrouter/anthropic/claude-3.5-sonnet

I haven't had to worry about the rate limit as of my last round of heavy usage, roughly June 2024. But if I do, this workaround is something to keep in mind.

Support installation as standalone program via `pipx`

The only hurdle I can foresee is that the end user needs to provide an API key. I could add a command line option to provide a path to the key in a file, or I could tell users to set an API key variable in their personal shell setup.

pipx might offer a way to advise users to do this.

Learn how to use `dataclasses.field` correctly for mutables

See here:

@dataclass
class GameSession:
db: sqlite_utils.Database
narration: str
call_to_action: str = "What do you do?"
id: str = str(ULID()).lower()
# TODO learn to use field here; I cargo-culted field(default_factory=lambda: players) but that seems wrong
def __post_init__(self):
self.actions_this_round: list[str] = list()
self.actions_previous_round: list[str] = list()
self.players = deepcopy(players)

I just stuck the players initialization in __post_init__ but using dataclasses.field would be more correct, I think? I originally cargo-culted field(default_factory=lambda: players) but that seems wrong. Ah well, not a huge issue.

LLMs, when told to do nothing / skip a turn, get confused and play as their companions

The leadup:

GM: The missile strikes true and deals 5 damage. Creatures of an ordinary biology, who take more than a quarter of their current hit points and damage, are stunned and lose a turn. This creature is not stunned. Whether it has high hit points or unusual biology is up to you to guess. Alice, roll a d20 for Arvak.

Arvak: I rolled a 14. What does that mean for Arvak? Does he notice any effect from the magic missile striking the creature?

Bolzar: calls out to Arvak The missile struck, but this thing is tougher than it looks! Stay on guard! turns to the GM Based on its resistance to the magic missile, I'm guessing this creature either has formidable hit points or some inherent defense against magic. Does the impact site show any visible cracks, scorch marks, or signs that the missile penetrated its rocky exterior? I want to gauge if physical attacks from Arvak might be more effective than my spells.

My next input:

GM: No physical signs of impact, unfortunately. Arvak, the 14 means you take only HALF damage when ... the creature tilts its base toward you and barrages you with a laser-like blast. You take 7 damage instead of 14, but that's enough to stun. Skip your next turn. Bolzar, your move.

The problematic response:

Arvak: curses under my breath as I see Arvak get blasted by the laser attack and stagger back, stunned

quickly calls out to him Arvak! Hold on, I'll draw its fire!

turns to the GM I'll cast Levitate on the pyramid creature, attempting to lift it further up into the air and hold it immobile. If I can get it high enough off the ground, it may not be able to target us with that laser barrage.

begins quickly reciting the incantation and making the somatic gestures to unleash the Levitate spell, targeting the hovering entity and putting as much power as I can muster into the casting

If the spell takes hold, how high can I lift the pyramid and how long will I be able to hold it suspended?**

(Bolzar then follows up with *almost the same exact things Arvak said while "confused":)

Bolzar: curses under my breath as I see Arvak get blasted by the laser attack and stagger back, stunned

quickly calls out to him Arvak! Hold on, I'll draw its fire!

turns to the GM I'll cast Levitate on the pyramid creature, attempting to lift it further up into the air and hold it immobile. If I can get it high enough off the ground, it may not be able to target us with that laser barrage.

begins quickly reciting the incantation and making the somatic gestures to unleash the Levitate spell, targeting the hovering entity and putting as much power as I can muster into the casting

If the spell takes hold, how high can I lift the pyramid and how long will I be able to hold it suspended?

keeps a wary eye on the creature as I cast, ready to dodge aside if it retaliates, while praying silently that my magic can halt its assault long enough for Arvak to recover

Add CLI flags for the initial scenario narration

This could take a string given on the command line, which is useful for quick experimentation scenarios. But the more useful interaction paradigm would be naming a file which will be read in to get the initial scenario text. This would allow the user to carefully craft an introductory narrative at length, in a text editor (rather than in the very limited readline bindings environment of the terminal.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.