Skip to main content
Glama
character.ts5.09 kB
import { z } from 'zod'; import { CharacterTypeSchema } from './party.js'; import { SubclassSchema, SpellSlotsSchema, PactMagicSlotsSchema, SpellcastingAbilitySchema } from './spell.js'; export const CharacterSchema = z.object({ id: z.string(), name: z.string() .min(1, 'Character name cannot be empty') .max(100, 'Character name cannot exceed 100 characters'), stats: z.object({ str: z.number().int().min(0), dex: z.number().int().min(0), con: z.number().int().min(0), int: z.number().int().min(0), wis: z.number().int().min(0), cha: z.number().int().min(0), }), hp: z.number().int().min(0), maxHp: z.number().int().min(0), ac: z.number().int().min(0), level: z.number().int().min(1), xp: z.number().int().min(0).default(0).describe('Current experience points'), characterType: CharacterTypeSchema.optional().default('pc'), // PHASE-2: Social Hearing Mechanics - skill bonuses for opposed rolls perceptionBonus: z.number().int().optional().default(0) .describe('Proficiency bonus for Perception checks (WIS-based)'), stealthBonus: z.number().int().optional().default(0) .describe('Proficiency bonus for Stealth checks (DEX-based)'), // Spellcasting fields (CRIT-002/006) // Flexible character class - allows any string (standard D&D classes or custom like "Chronomancer") characterClass: z.string().optional().default('fighter'), race: z.string().optional().default('Human') .describe('Character race - any string allowed (Human, Elf, Dragonborn, Mousefolk...)'), subclass: SubclassSchema.optional(), spellSlots: SpellSlotsSchema.optional(), pactMagicSlots: PactMagicSlotsSchema.optional(), // Warlock only knownSpells: z.array(z.string()).optional().default([]), preparedSpells: z.array(z.string()).optional().default([]), cantripsKnown: z.array(z.string()).optional().default([]), maxSpellLevel: z.number().int().min(0).max(9).optional().default(0), spellcastingAbility: SpellcastingAbilitySchema.optional(), spellSaveDC: z.number().int().optional(), spellAttackBonus: z.number().int().optional(), concentratingOn: z.string().nullable().optional().default(null), activeSpells: z.array(z.string()).optional().default([]), conditions: z.array(z.object({ name: z.string().describe('Condition name (e.g., Poisoned, Frightened)'), duration: z.number().int().optional().describe('Duration in rounds'), source: z.string().optional().describe('Source of the condition') })).optional().default([]), position: z.object({ x: z.number(), y: z.number() }).optional(), // PHASE-1: Spatial Graph System - current room for spatial awareness currentRoomId: z.string().uuid().optional() .describe('ID of the room the character is currently in'), // HIGH-007: Legendary creature fields legendaryActions: z.number().int().min(0).optional() .describe('Total legendary actions per round (usually 3)'), legendaryActionsRemaining: z.number().int().min(0).optional() .describe('Remaining legendary actions this round'), legendaryResistances: z.number().int().min(0).optional() .describe('Total legendary resistances per day (usually 3)'), legendaryResistancesRemaining: z.number().int().min(0).optional() .describe('Remaining legendary resistances'), hasLairActions: z.boolean().optional().default(false) .describe('Whether this creature can use lair actions on initiative 20'), // HIGH-002: Damage modifiers resistances: z.array(z.string()).optional().default([]) .describe('Damage types that deal half damage (e.g., ["fire", "cold"])'), vulnerabilities: z.array(z.string()).optional().default([]) .describe('Damage types that deal double damage'), immunities: z.array(z.string()).optional().default([]) .describe('Damage types that deal no damage'), // Skill and Save Proficiencies skillProficiencies: z.array(z.enum([ 'acrobatics', 'animal_handling', 'arcana', 'athletics', 'deception', 'history', 'insight', 'intimidation', 'investigation', 'medicine', 'nature', 'perception', 'performance', 'persuasion', 'religion', 'sleight_of_hand', 'stealth', 'survival' ])).optional().default([]).describe('Skills the character is proficient in'), saveProficiencies: z.array(z.enum(['str', 'dex', 'con', 'int', 'wis', 'cha'])) .optional().default([]).describe('Saving throws the character is proficient in'), expertise: z.array(z.string()).optional().default([]) .describe('Skills with double proficiency bonus (rogues, bards)'), createdAt: z.string().datetime(), updatedAt: z.string().datetime(), }); export type Character = z.infer<typeof CharacterSchema>; export const NPCSchema = CharacterSchema.extend({ factionId: z.string().optional(), behavior: z.string().optional(), }); export type NPC = z.infer<typeof NPCSchema>;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/rpg-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server