Jeg har tænkt på at lave en multiplayer RPG webplatform siden mine dage som en Flash-udvikler.Der er masser af online TTRPG-muligheder derude (mange gode!) men ingen af dem følte sig helt rigtige for, hvordan jeg ville spille. Har du set hvor Deborah Ann Woll viser Jon Bernthal, hvordan man spiller D&D? (det har 2M views!) Den video https://www.youtube.com/watch?v=JpVJZrabMQE&embedable=true Det var så fedt. Hvad hvis jeg kunne lave noget, der føles sådan? Idéen En fortællingsdrevet, multiplayer online rpg platform, let på regler, men høj på delt historiefortælling, med resultater bestemmes af rollen af en D20. Jeg har altid elsket Den spændende introduktion.De detaljerede møder og episke historie planer for spillerne at opdage, som deres karakterer gør deres vej gennem til en klimatiske finale. D&D moduler Hvad hvis jeg kunne skabe en måde for folk at lave deres egne eventyrmoduler, for enhver RPG genre, så lad spillerne køre deres karakterer gennem disse eventyr? Hvem ville køre spillene? spilmestere er svære at finde. Hvad hvis jeg kunne træne en AI til at være en spilmester? For faktisk at køre en velstruktureret eventyrplan (designet af et menneske!) som ville være sjovt for spillere og ikke bare en masse ? Jeg slæber At blive startet Jeg har haft det sjovt at bygge mange ting med AI (se Jeg vil bruge min foretrukne stack til at lave , en Next.js webapp med Tailwind til brugergrænseflade (behøver det endda siges?) drevet af Gemini og A Udstillet til Vercel. Mit projekt starter D20Adventures.com Læs mere Hvad er SDK Convex databaser Og jeg har besluttet at bygge det i det åbne, offentliggøre koden . af Github Den prototype For en prototype starter jeg bogstaveligt talt fra scenariet på podcasten, en ranger, der går gennem skoven om natten, hører et knæk i afstand, som viser sig at være en ørnebær. Mit mål er at opbygge et kort one-shot-eventyr og se, om jeg kan træne en AI DM til faktisk at køre en lille serie af omdrejninger og møder til dette eventyr. Midnat Summons En mystisk opfordring fra en gammel druidisk ven trækker en tilbageholdt ranger ind i vildmarken i Valkarr-skoven. Midnat Summons En mystisk opfordring fra en gammel druidisk ven trækker en tilbageholdt ranger ind i vildmarken i Valkarr-skoven. Efter mange forsøg og fejl, var jeg endelig i stand til at gøre et fuldt spil igennem og offentliggøre det på YouTube: https://youtu.be/9wzNVmhVMlg?si=qaNEJ8wcF4bzZJK9&embedable=true Hvordan det virker Landing Page Landingssiden er et stort helt billede (genereret på Midjourney med en prompt af "The Power of the D20"). jeg tilføjede nogle enkle fade i animation ved hjælp af den nye CSS @starting-stil regel: .fade-in { @apply opacity-100 transition-opacity duration-1000 ease-in-out; @starting-style { opacity: 0; } } Authentication Dette er for at undgå at blive opkrævet en masse penge på grund af anonyme mennesker eller bots, der bruger mine API'er. gør det meget nemt at tilføje brugeradministration, og jeg bruger dem på alle mine projekter. Klerik Derudover har jeg token brug sporing, hvor jeg vil begrænse brugen med et token system, hvor du starter med nok tokens til at gøre et spil igennem af demoen, så kan du købe mere, som du går. The First Turn Når brugeren lander på eventyrsiden for den hurtige start, er det første, der sker, at vi indlæser dataene til demo-eventyret, som kun er en simpel JSON-fil ( En eventyrmodul eller plan i mit system består af en serie af møder, som er forbundet med hinanden med instruktioner til LLM: Sådan her "encounters": [ { "id": "broken-silence", "title": "Broken Silence", "intro": "Thalbern, a solitary ranger of the Valkarr woods, has always trusted the silence of the wilds more than the promises of men. Orphaned by border raiders and raised by the elves of the Valkrarr Forest, he has spent years living on the edge of Kordavos, guiding travelers, hunting for his own survival, and keeping his distance from the tangled politics of the city.\n\nYet on this night, a message delivered by a red squirrel bearing the unmistakable script of Wollandora, a trusted elven friend and druid, has drawn him from his hidden home. The note was simple and urgent: Meet me at the Old Standing Stones at midnight. The balance of the forest could depend on it.\n\nNow, as midnight approaches, Thalbern moves quietly through the dense undergrowth, guided by memory and instinct. It is dark with almost no moonlight coming through the forest canopy.\n\nSuddenly, the hush of the night is broken by a sharp crack. Something large has just stepped on a branch somewhere off in the distance.", "instructions": "A perception check is appropriate if Thalbern investigates (low difficulty with a plus 3 modifier). If successful, he will determine it is a large creature that is approaching quickly. With a high roll (18+), he will determine it is an Owlbear. If combat ensues and Thalbern is below 25% health, Wollandora will intervene. If Thalbern avoids or defeats the Owlbear, or if Wollandora saves him, he proceeds to the Old Standing Stones.", "image": "images/settings/realm-of-myr/the-midnight-summons/broken-silence-2.png", "transitions": [ { "condition": "If Thalbern successfully uses stealth to evade and proceeds cautiously towards the Standing Stones, go to meeting-at-stones.", "encounter": "meeting-at-stones" }, { "condition": "If Thalbern fails a perception check, advance to owlbear-confrontation.", "encounter": "owlbear-confrontation" }, { "condition": "If Thalbern fails any dice roll (including stealth, perception, or any other check), advance to owlbear-confrontation.", "encounter": "owlbear-confrontation" }, { "condition": "If Thalbern does NOT successfully use stealth to evade, go to owlbear-confrontation.", "encounter": "owlbear-confrontation" }, { "condition": "If Thalbern does nothing or takes no action, go to owlbear-confrontation.", "encounter": "owlbear-confrontation" }, { "condition": "If Thalbern has a healthPercent of less than 50%, go to wollandora-intervention.", "encounter": "wollandora-intervention" } ] }, { "id": "owlbear-confrontation", "title": "Owlbear Confrontation", "intro": "From the direction of the sound, a little bit of eye shine glints in the shadows of the tree line. A hulking fifteen foot tall monster with the body of a giant bear and the head of an owl. As it crashes out from the undergrowth, it lets out a guttural squawk, clearly agitated and territorial.", "instructions": "The Owlbear will attack. If Thalbern attempts an animal handling check (high difficulty) and succeeds, he can move past the Owlbear. If Thalbern wins initiative and attempts to hide, he can move past the Owlbear if he passes a medium difficulty stealth check. If Thalbern's health drops to a critical level, Wollandora appears and drives off the Owlbear, transitioning to 'wollandora-intervention'. If Thalbern defeats the Owlbear, describe his victory and transition to 'meeting-at-stones'.", "image": "images/settings/realm-of-myr/the-midnight-summons/owlbear-confrontation.png", "npc": [ { "id": "owlbear", "behavior": "Aggressively attacks any perceived threat. Will fight until heavily wounded or driven off.", "initialInitiative": 1 } ], "transitions": [ { "condition": "Thalbern defeats the Owlbear, manages to evade it, successfully uses Animal Handling to pacify and move past it, or successfully rolls any other way to move past it.", "encounter": "meeting-at-stones" }, { "condition": "Thalbern is reduced to critical health by the Owlbear.", "encounter": "timely-rescue" } ] }, ... ] The First Reply Da vi er i demo-tilstand, er der ingen reel eventyr skabt endnu på backend. Det sker, når spilleren gør det første svar. funktion, der bruger AI til at evaluere svaret for at sikre, at det er grammatisk korrekt, i tredje person og tilføjer dialog eller anden prosa for at få det til at fungere godt i en litterær fortællingsstil. formatNarrativeAction Når formateringen er anvendt, sendes svaret til en serveraktion. Fordi dette er en demo, skaber vi eventyret i databasen, når dette første svar modtages. Processing Player Responses Den Funktionen indlæser den aktuelle tur fra Convex, eventyrdataene fra S3, og identificerer det specifikke møde og den karakter, der udfører handlingen. processTurnReply I denne sammenhæng bruger det derefter AI til at afgøre, om handlingen er plausibel (min søn, da han spillede test, havde ranger lanceret en nuke på ørnbjørnen) og, hvis ja, om en dick roll er mekanisk nødvendig (f.eks. en "Attack Roll" eller en "Stealth Check"), herunder typen af roll og dens sværhedsgrad. Vi kan gøre dette med et funktionsopkald, hvor vi kan angive til AI, at vi vil have strukturerede data returneret, i dette tilfælde en : rollRequirementSchema import { z } from "zod"; export const rollRequirementSchema = z.union([ z.object({ rollType: z.string().describe("The type of roll required, e.g. 'Stealth Check'"), difficulty: z.number().describe("The difficulty class (DC) for the roll"), modifier: z.number().optional().describe("Bonus or penalty to the roll, e.g. +2 or -1"), }), z.null() ]); export type RollRequirement = z.infer<typeof rollRequirementSchema>; Så har vi en funktion, der sender en detaljeret prompt og skemaet til : generateObject export async function getRollRequirementForAction(action: string) { const prompt = ` Given the following player or NPC action, determine if a dice roll is required for the character to attempt the action. If a roll is required, return a JSON object with "rollType" (choose the most appropriate from the list below) and "difficulty" (a number between 5 and 25). If no roll is required, return the JSON value null (not a string). Possible roll types: - Perception Check - Investigation Check - Insight Check - Stealth Check ... Examples: Action: "Try to sneak past the guards." Result: { "rollType": "Stealth Check", "difficulty": 15 } Action: "Attack the goblin." Result: { "rollType": "Attack Roll", "difficulty": 12 } Action: "Try to determine what the sound is." Result: { "rollType": "Perception Check", "difficulty": 10 } Action: "Say hello." Result: null Now, given the following action, determine the roll requirement. Action: "${action}" `; try { const result = await generateObject({ schema: rollRequirementSchema, prompt, }); if ( result.object && typeof result.object === "object" && "rollType" in result.object && (result.object.rollType === "null" || result.object.rollType === "none" || result.object.rollType === "") ) { return null; } return result.object ?? null; } catch (error) { throw error; } } Efter at have tilføjet spillerens svar til turens historie, hvis der kræves en terningrulle, opdaterer vi karakterens tilstand i konvexrullen for at afspejle, at de har svaret, men deres tur ikke er fuldført. Når brugeren ruller, har vi en Server action, der opdaterer fortællingen med en visuel visning af resultatet og skriver prosa, der beskriver resultatet.Vi har også en anden AI-funktion opkald til at opdatere sundhed og status for alle tegnene i tur. resolvePlayerRollResult NPC Actions Når det er en NPCs tur til at svare, følger vi et lignende mønster som en spiller, undtagen i dette tilfælde AI vil skrive svaret. Hver møde indeholder oplysninger om NPCs motivation og når kombineret med konteksten af eventyrfortællingen hidtil, forhåbentlig AI kan generere et godt svar, så generere sin egen dick roll og resultat opdatering. Training AI to Run RPGs Hvis du nogensinde har forsøgt at lave en spil session med AI i en chat, ved du, hvor hurtigt det kan gå af sporet. Forhåbentlig ved at give den passende kontekst, specifikke promptinstruktioner og strukturerede datafunktion opkald, kan vi få en oplevelse, der er behagelig. Der er helt sikkert en masse prøve og fejl, konsollogging og prompt tweaking. For eksempel, når jeg spurgte, hvorfor AI ikke fulgte mødevejledningen i en af mine testløb, var det her, hvad Cursor chat havde at sige til mig: Sammenfattende fulgte LLM ikke sine eksplicitte instruktioner til overgang, når en karakter fejler en opfattelseskontrol, på trods af at være forsynet med klare beviser for et sådant fiasko og en overgangsregel for det specifikke scenarie. Sammenfattende fulgte LLM ikke sine eksplicitte instruktioner til overgang, når en karakter fejler en opfattelseskontrol, på trods af at være forsynet med klare beviser for et sådant fiasko og en overgangsregel for det specifikke scenarie. Jeg tror, at tilfældigheden af AI ikke gør præcis, hvad der forventes, kan være en del af det sjove. Her er et eksempel på . En af spillets sessioner Du kan se hele kildekoden for dette projekt på på github.com/johnpolacek/d20adventures.com