Skip to main content
Glama
spell.ts7.51 kB
import { z } from 'zod'; // Spell schools from D&D 5e export const SpellSchoolSchema = z.enum([ 'abjuration', 'conjuration', 'divination', 'enchantment', 'evocation', 'illusion', 'necromancy', 'transmutation' ]); export type SpellSchool = z.infer<typeof SpellSchoolSchema>; // Casting time types export const CastingTimeSchema = z.enum([ 'action', 'bonus_action', 'reaction', 'minute', '10_minutes', 'hour', '8_hours', '12_hours', '24_hours' ]); export type CastingTime = z.infer<typeof CastingTimeSchema>; // Spell range types export const SpellRangeSchema = z.union([ z.literal('self'), z.literal('touch'), z.number().int().min(0) // Distance in feet ]); export type SpellRange = z.infer<typeof SpellRangeSchema>; // Damage types export const DamageTypeSchema = z.enum([ 'acid', 'bludgeoning', 'cold', 'fire', 'force', 'lightning', 'necrotic', 'piercing', 'poison', 'psychic', 'radiant', 'slashing', 'thunder' ]); export type DamageType = z.infer<typeof DamageTypeSchema>; // Save types export const SaveTypeSchema = z.enum([ 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma', 'none' ]); export type SaveType = z.infer<typeof SaveTypeSchema>; // Spell components export const SpellComponentsSchema = z.object({ verbal: z.boolean(), somatic: z.boolean(), material: z.boolean(), materialDescription: z.string().optional() }); export type SpellComponents = z.infer<typeof SpellComponentsSchema>; // Spell target types export const SpellTargetTypeSchema = z.enum([ 'self', 'creature', 'creatures', 'point', 'area', 'object' ]); export type SpellTargetType = z.infer<typeof SpellTargetTypeSchema>; // Area of effect shapes export const AreaShapeSchema = z.enum([ 'cone', 'cube', 'cylinder', 'line', 'sphere' ]); export type AreaShape = z.infer<typeof AreaShapeSchema>; // Spell effect schema export const SpellEffectSchema = z.object({ type: z.enum(['damage', 'healing', 'buff', 'debuff', 'utility', 'summon']), dice: z.string().optional(), // e.g., "8d6", "1d8+4" damageType: DamageTypeSchema.optional(), saveType: SaveTypeSchema.optional(), saveEffect: z.enum(['half', 'none', 'special']).optional(), // What happens on successful save upcastBonus: z.object({ dice: z.string(), // Additional dice per level, e.g., "1d6" perLevel: z.number().int().default(1) // How many levels for the bonus }).optional(), conditions: z.array(z.string()).optional() // Conditions applied }); export type SpellEffect = z.infer<typeof SpellEffectSchema>; // Class list for spell availability export const SpellcastingClassSchema = z.enum([ 'bard', 'cleric', 'druid', 'paladin', 'ranger', 'sorcerer', 'warlock', 'wizard', 'artificer' ]); export type SpellcastingClass = z.infer<typeof SpellcastingClassSchema>; // Complete spell definition export const SpellSchema = z.object({ id: z.string(), name: z.string(), level: z.number().int().min(0).max(9), // 0 = cantrip school: SpellSchoolSchema, castingTime: CastingTimeSchema, range: SpellRangeSchema, components: SpellComponentsSchema, duration: z.string(), // e.g., "Instantaneous", "1 minute", "Concentration, up to 1 hour" concentration: z.boolean(), ritual: z.boolean().optional().default(false), description: z.string(), higherLevels: z.string().optional(), // Description for upcasting classes: z.array(SpellcastingClassSchema), targetType: SpellTargetTypeSchema, areaOfEffect: z.object({ shape: AreaShapeSchema, size: z.number().int() // Size in feet }).optional(), effects: z.array(SpellEffectSchema), autoHit: z.boolean().default(false) // e.g., Magic Missile }); export type Spell = z.infer<typeof SpellSchema>; // Spell slot schema for characters export const SpellSlotSchema = z.object({ current: z.number().int().min(0), max: z.number().int().min(0) }); export type SpellSlot = z.infer<typeof SpellSlotSchema>; // Full spell slots by level (1-9) export const SpellSlotsSchema = z.object({ level1: SpellSlotSchema.default({ current: 0, max: 0 }), level2: SpellSlotSchema.default({ current: 0, max: 0 }), level3: SpellSlotSchema.default({ current: 0, max: 0 }), level4: SpellSlotSchema.default({ current: 0, max: 0 }), level5: SpellSlotSchema.default({ current: 0, max: 0 }), level6: SpellSlotSchema.default({ current: 0, max: 0 }), level7: SpellSlotSchema.default({ current: 0, max: 0 }), level8: SpellSlotSchema.default({ current: 0, max: 0 }), level9: SpellSlotSchema.default({ current: 0, max: 0 }) }); export type SpellSlots = z.infer<typeof SpellSlotsSchema>; // Warlock pact magic slots (all same level) export const PactMagicSlotsSchema = z.object({ current: z.number().int().min(0), max: z.number().int().min(0), slotLevel: z.number().int().min(1).max(5) // Warlock slots max at 5th level }); export type PactMagicSlots = z.infer<typeof PactMagicSlotsSchema>; // Spellcasting ability mapping export const SpellcastingAbilitySchema = z.enum([ 'intelligence', 'wisdom', 'charisma' ]); export type SpellcastingAbility = z.infer<typeof SpellcastingAbilitySchema>; // Character class schema (for spellcasting validation) export const CharacterClassSchema = z.enum([ 'barbarian', 'bard', 'cleric', 'druid', 'fighter', 'monk', 'paladin', 'ranger', 'rogue', 'sorcerer', 'warlock', 'wizard', 'artificer' ]); export type CharacterClass = z.infer<typeof CharacterClassSchema>; // Subclass schema for third-casters export const SubclassSchema = z.enum([ 'eldritch_knight', // Fighter 'arcane_trickster', // Rogue 'champion', // Fighter (non-caster) 'assassin', // Rogue (non-caster) 'none' ]).default('none'); export type Subclass = z.infer<typeof SubclassSchema>; // Cast spell request schema (for validation) export const CastSpellRequestSchema = z.object({ characterId: z.string(), spellName: z.string().min(1, 'Spell name is required'), slotLevel: z.number().int().min(1).max(9).optional(), targetId: z.string().optional(), targetPoint: z.object({ x: z.number(), y: z.number() }).optional(), asReaction: z.boolean().optional(), metamagic: z.array(z.string()).optional() }); export type CastSpellRequest = z.infer<typeof CastSpellRequestSchema>; // Spell cast result schema export const SpellCastResultSchema = z.object({ success: z.boolean(), spellName: z.string(), slotUsed: z.number().int().optional(), // undefined for cantrips damage: z.number().int().optional(), damageType: DamageTypeSchema.optional(), healing: z.number().int().optional(), diceRolled: z.string().optional(), saveResult: z.enum(['passed', 'failed', 'none']).optional(), damageRolled: z.number().int().optional(), damageApplied: z.number().int().optional(), autoHit: z.boolean().optional(), attackRoll: z.number().int().optional(), acBonus: z.number().int().optional(), // For Shield dartCount: z.number().int().optional(), // For Magic Missile concentration: z.boolean().optional(), error: z.string().optional() }); export type SpellCastResult = z.infer<typeof SpellCastResultSchema>;

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