Skip to main content
Glama
spell-database.ts21.1 kB
/** * Spell Database - Core D&D 5e SRD Spells * Used for validation against LLM hallucination (CRIT-006) */ import type { Spell, SpellcastingClass } from '../../schema/spell.js'; // Full spell database export const SPELL_DATABASE: Map<string, Spell> = new Map(); // Input type for spell registration (ritual defaults to false) type SpellInput = Omit<Spell, 'ritual'> & { ritual?: boolean }; // Helper to add spell to database function registerSpell(input: SpellInput): void { const spell: Spell = { ...input, ritual: input.ritual ?? false }; SPELL_DATABASE.set(spell.name.toLowerCase(), spell); } // ============================================================================ // CANTRIPS (Level 0) // ============================================================================ registerSpell({ id: 'fire-bolt', name: 'Fire Bolt', level: 0, school: 'evocation', castingTime: 'action', range: 120, components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'You hurl a mote of fire at a creature or object within range.', classes: ['sorcerer', 'wizard', 'artificer'], targetType: 'creature', effects: [{ type: 'damage', dice: '1d10', // Scales: 2d10 at 5th, 3d10 at 11th, 4d10 at 17th damageType: 'fire', saveType: 'none' }], autoHit: false }); registerSpell({ id: 'sacred-flame', name: 'Sacred Flame', level: 0, school: 'evocation', castingTime: 'action', range: 60, components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'Flame-like radiance descends on a creature that you can see within range.', classes: ['cleric'], targetType: 'creature', effects: [{ type: 'damage', dice: '1d8', // Scales like Fire Bolt damageType: 'radiant', saveType: 'dexterity', saveEffect: 'none' }], autoHit: false }); registerSpell({ id: 'eldritch-blast', name: 'Eldritch Blast', level: 0, school: 'evocation', castingTime: 'action', range: 120, components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'A beam of crackling energy streaks toward a creature within range.', classes: ['warlock'], targetType: 'creature', effects: [{ type: 'damage', dice: '1d10', // Multiple beams at higher levels damageType: 'force', saveType: 'none' }], autoHit: false }); // ============================================================================ // 1ST LEVEL SPELLS // ============================================================================ registerSpell({ id: 'magic-missile', name: 'Magic Missile', level: 1, school: 'evocation', castingTime: 'action', range: 120, components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'You create three glowing darts of magical force. Each dart hits and deals 1d4+1 force damage.', higherLevels: 'One additional dart for each slot level above 1st.', classes: ['sorcerer', 'wizard'], targetType: 'creature', effects: [{ type: 'damage', dice: '3d4+3', // 3 darts at 1d4+1 each damageType: 'force', saveType: 'none', upcastBonus: { dice: '1d4+1', perLevel: 1 } // +1 dart per level }], autoHit: true // Magic Missile never misses }); registerSpell({ id: 'shield', name: 'Shield', level: 1, school: 'abjuration', castingTime: 'reaction', range: 'self', components: { verbal: true, somatic: true, material: false }, duration: '1 round', concentration: false, description: 'An invisible barrier of magical force appears and protects you. +5 AC until the start of your next turn.', classes: ['sorcerer', 'wizard'], targetType: 'self', effects: [{ type: 'buff', conditions: ['AC_BONUS_5'] }], autoHit: false }); registerSpell({ id: 'cure-wounds', name: 'Cure Wounds', level: 1, school: 'evocation', castingTime: 'action', range: 'touch', components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'A creature you touch regains a number of hit points equal to 1d8 + your spellcasting ability modifier.', higherLevels: 'Healing increases by 1d8 for each slot level above 1st.', classes: ['bard', 'cleric', 'druid', 'paladin', 'ranger', 'artificer'], targetType: 'creature', effects: [{ type: 'healing', dice: '1d8', upcastBonus: { dice: '1d8', perLevel: 1 } }], autoHit: false }); registerSpell({ id: 'hex', name: 'Hex', level: 1, school: 'enchantment', castingTime: 'bonus_action', range: 90, components: { verbal: true, somatic: true, material: true, materialDescription: 'the petrified eye of a newt' }, duration: 'Concentration, up to 1 hour', concentration: true, description: 'You place a curse on a creature that you can see within range. Deal extra 1d6 necrotic damage on hits.', higherLevels: 'Duration increases with higher slots.', classes: ['warlock'], targetType: 'creature', effects: [{ type: 'debuff', dice: '1d6', damageType: 'necrotic', conditions: ['HEXED'] }], autoHit: false }); registerSpell({ id: 'burning-hands', name: 'Burning Hands', level: 1, school: 'evocation', castingTime: 'action', range: 'self', components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'A thin sheet of flames shoots forth from your outstretched fingertips.', higherLevels: 'Damage increases by 1d6 for each slot level above 1st.', classes: ['sorcerer', 'wizard'], targetType: 'area', areaOfEffect: { shape: 'cone', size: 15 }, effects: [{ type: 'damage', dice: '3d6', damageType: 'fire', saveType: 'dexterity', saveEffect: 'half', upcastBonus: { dice: '1d6', perLevel: 1 } }], autoHit: false }); registerSpell({ id: 'misty-step', name: 'Misty Step', level: 2, school: 'conjuration', castingTime: 'bonus_action', range: 'self', components: { verbal: true, somatic: false, material: false }, duration: 'Instantaneous', concentration: false, description: 'Briefly surrounded by silvery mist, you teleport up to 30 feet to an unoccupied space.', classes: ['sorcerer', 'warlock', 'wizard'], targetType: 'self', effects: [{ type: 'utility' }], autoHit: false }); // ============================================================================ // 2ND LEVEL SPELLS // ============================================================================ registerSpell({ id: 'hold-person', name: 'Hold Person', level: 2, school: 'enchantment', castingTime: 'action', range: 60, components: { verbal: true, somatic: true, material: true, materialDescription: 'a small, straight piece of iron' }, duration: 'Concentration, up to 1 minute', concentration: true, description: 'Choose a humanoid that you can see within range. The target must succeed on a Wisdom saving throw or be paralyzed.', higherLevels: 'Target one additional humanoid for each slot level above 2nd.', classes: ['bard', 'cleric', 'druid', 'sorcerer', 'warlock', 'wizard'], targetType: 'creature', effects: [{ type: 'debuff', saveType: 'wisdom', saveEffect: 'none', conditions: ['PARALYZED'] }], autoHit: false }); registerSpell({ id: 'spiritual-weapon', name: 'Spiritual Weapon', level: 2, school: 'evocation', castingTime: 'bonus_action', range: 60, components: { verbal: true, somatic: true, material: false }, duration: '1 minute', concentration: false, description: 'You create a floating, spectral weapon within range that lasts for the duration.', higherLevels: 'Damage increases by 1d8 for every two slot levels above 2nd.', classes: ['cleric'], targetType: 'point', effects: [{ type: 'damage', dice: '1d8', damageType: 'force', upcastBonus: { dice: '1d8', perLevel: 2 } }], autoHit: false }); // ============================================================================ // 3RD LEVEL SPELLS // ============================================================================ registerSpell({ id: 'fireball', name: 'Fireball', level: 3, school: 'evocation', castingTime: 'action', range: 150, components: { verbal: true, somatic: true, material: true, materialDescription: 'a tiny ball of bat guano and sulfur' }, duration: 'Instantaneous', concentration: false, description: 'A bright streak flashes from your pointing finger to a point you choose within range and then blossoms with a low roar into an explosion of flame.', higherLevels: 'Damage increases by 1d6 for each slot level above 3rd.', classes: ['sorcerer', 'wizard'], targetType: 'point', areaOfEffect: { shape: 'sphere', size: 20 }, effects: [{ type: 'damage', dice: '8d6', damageType: 'fire', saveType: 'dexterity', saveEffect: 'half', upcastBonus: { dice: '1d6', perLevel: 1 } }], autoHit: false }); registerSpell({ id: 'lightning-bolt', name: 'Lightning Bolt', level: 3, school: 'evocation', castingTime: 'action', range: 'self', components: { verbal: true, somatic: true, material: true, materialDescription: 'a bit of fur and a rod of amber, crystal, or glass' }, duration: 'Instantaneous', concentration: false, description: 'A stroke of lightning forming a line 100 feet long and 5 feet wide blasts out from you.', higherLevels: 'Damage increases by 1d6 for each slot level above 3rd.', classes: ['sorcerer', 'wizard'], targetType: 'area', areaOfEffect: { shape: 'line', size: 100 }, effects: [{ type: 'damage', dice: '8d6', damageType: 'lightning', saveType: 'dexterity', saveEffect: 'half', upcastBonus: { dice: '1d6', perLevel: 1 } }], autoHit: false }); registerSpell({ id: 'counterspell', name: 'Counterspell', level: 3, school: 'abjuration', castingTime: 'reaction', range: 60, components: { verbal: false, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'You attempt to interrupt a creature in the process of casting a spell.', higherLevels: 'Automatically counter spells of 3rd level or lower. Higher levels require ability check.', classes: ['sorcerer', 'warlock', 'wizard'], targetType: 'creature', effects: [{ type: 'utility' }], autoHit: false }); // ============================================================================ // 4TH LEVEL SPELLS // ============================================================================ registerSpell({ id: 'dimension-door', name: 'Dimension Door', level: 4, school: 'conjuration', castingTime: 'action', range: 500, components: { verbal: true, somatic: false, material: false }, duration: 'Instantaneous', concentration: false, description: 'You teleport yourself to any spot within range.', classes: ['bard', 'sorcerer', 'warlock', 'wizard'], targetType: 'self', effects: [{ type: 'utility' }], autoHit: false }); // ============================================================================ // 5TH LEVEL SPELLS // ============================================================================ registerSpell({ id: 'haste', name: 'Haste', level: 3, school: 'transmutation', castingTime: 'action', range: 30, components: { verbal: true, somatic: true, material: true, materialDescription: 'a shaving of licorice root' }, duration: 'Concentration, up to 1 minute', concentration: true, description: 'Choose a willing creature. Until the spell ends, the target\'s speed is doubled, it gains +2 AC, has advantage on Dexterity saving throws, and gains an additional action.', classes: ['sorcerer', 'wizard', 'artificer'], targetType: 'creature', effects: [{ type: 'buff', conditions: ['HASTED'] }], autoHit: false }); registerSpell({ id: 'fly', name: 'Fly', level: 3, school: 'transmutation', castingTime: 'action', range: 'touch', components: { verbal: true, somatic: true, material: true, materialDescription: 'a wing feather from any bird' }, duration: 'Concentration, up to 10 minutes', concentration: true, description: 'You touch a willing creature. The target gains a flying speed of 60 feet for the duration.', higherLevels: 'Target one additional creature for each slot level above 3rd.', classes: ['sorcerer', 'warlock', 'wizard', 'artificer'], targetType: 'creature', effects: [{ type: 'buff', conditions: ['FLYING'] }], autoHit: false }); // ============================================================================ // 6TH LEVEL SPELLS // ============================================================================ registerSpell({ id: 'disintegrate', name: 'Disintegrate', level: 6, school: 'transmutation', castingTime: 'action', range: 60, components: { verbal: true, somatic: true, material: true, materialDescription: 'a lodestone and a pinch of dust' }, duration: 'Instantaneous', concentration: false, description: 'A thin green ray springs from your pointing finger. The target takes 10d6+40 force damage.', higherLevels: 'Damage increases by 3d6 for each slot level above 6th.', classes: ['sorcerer', 'wizard'], targetType: 'creature', effects: [{ type: 'damage', dice: '10d6+40', damageType: 'force', saveType: 'dexterity', saveEffect: 'none', // All or nothing upcastBonus: { dice: '3d6', perLevel: 1 } }], autoHit: false }); // ============================================================================ // 9TH LEVEL SPELLS // ============================================================================ registerSpell({ id: 'meteor-swarm', name: 'Meteor Swarm', level: 9, school: 'evocation', castingTime: 'action', range: 'self', // 1 mile actually but self for targeting components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'Blazing orbs of fire plummet to the ground at four different points you can see within range.', classes: ['sorcerer', 'wizard'], targetType: 'point', areaOfEffect: { shape: 'sphere', size: 40 }, effects: [{ type: 'damage', dice: '40d6', // 20d6 fire + 20d6 bludgeoning damageType: 'fire', saveType: 'dexterity', saveEffect: 'half' }], autoHit: false }); registerSpell({ id: 'power-word-kill', name: 'Power Word Kill', level: 9, school: 'enchantment', castingTime: 'action', range: 60, components: { verbal: true, somatic: false, material: false }, duration: 'Instantaneous', concentration: false, description: 'You utter a word of power that can compel one creature you can see within range to die instantly if it has 100 HP or less.', classes: ['bard', 'sorcerer', 'warlock', 'wizard'], targetType: 'creature', effects: [{ type: 'damage', conditions: ['INSTANT_DEATH'] }], autoHit: true }); registerSpell({ id: 'wish', name: 'Wish', level: 9, school: 'conjuration', castingTime: 'action', range: 'self', components: { verbal: true, somatic: false, material: false }, duration: 'Instantaneous', concentration: false, description: 'Wish is the mightiest spell a mortal creature can cast. By simply speaking aloud, you can alter the very foundations of reality in accord with your desires.', classes: ['sorcerer', 'wizard'], targetType: 'self', effects: [{ type: 'utility' }], autoHit: false }); registerSpell({ id: 'bless', name: 'Bless', level: 1, school: 'enchantment', castingTime: 'action', range: 30, components: { verbal: true, somatic: true, material: true, materialDescription: 'a sprinkling of holy water' }, duration: 'Concentration, up to 1 minute', concentration: true, description: 'You bless up to three creatures of your choice within range. Whenever a target makes an attack roll or saving throw, they can roll a d4 and add to the roll.', higherLevels: 'One additional creature for each slot level above 1st.', classes: ['cleric', 'paladin'], targetType: 'creatures', effects: [{ type: 'buff', dice: '1d4', conditions: ['BLESSED'] }], autoHit: false }); registerSpell({ id: 'guiding-bolt', name: 'Guiding Bolt', level: 1, school: 'evocation', castingTime: 'action', range: 120, components: { verbal: true, somatic: true, material: false }, duration: 'Instantaneous', concentration: false, description: 'A flash of light streaks toward a creature of your choice within range. On hit, the target takes 4d6 radiant damage and the next attack against it has advantage.', higherLevels: 'Damage increases by 1d6 for each slot level above 1st.', classes: ['cleric'], targetType: 'creature', effects: [{ type: 'damage', dice: '4d6', damageType: 'radiant', saveType: 'none', upcastBonus: { dice: '1d6', perLevel: 1 }, conditions: ['GLOWING'] }], autoHit: false }); // ============================================================================ // SPELL LOOKUP FUNCTIONS // ============================================================================ /** * Get spell by name (case-insensitive) */ export function getSpell(name: string): Spell | undefined { return SPELL_DATABASE.get(name.toLowerCase()); } /** * Check if spell exists in database */ export function spellExists(name: string): boolean { return SPELL_DATABASE.has(name.toLowerCase()); } /** * Get all spells of a specific level */ export function getSpellsByLevel(level: number): Spell[] { return Array.from(SPELL_DATABASE.values()).filter(s => s.level === level); } /** * Get all spells available to a class */ export function getSpellsForClass(characterClass: SpellcastingClass): Spell[] { return Array.from(SPELL_DATABASE.values()).filter(s => s.classes.includes(characterClass) ); } /** * Check if a spell is available to a specific class */ export function isSpellAvailableToClass(spellName: string, characterClass: SpellcastingClass): boolean { const spell = getSpell(spellName); if (!spell) return false; return spell.classes.includes(characterClass); } /** * Get all cantrips */ export function getCantrips(): Spell[] { return getSpellsByLevel(0); } /** * Calculate cantrip damage dice based on character level * Cantrips scale at 5th, 11th, and 17th level */ export function getCantripDice(baseCount: number, characterLevel: number): string { let diceCount = baseCount; if (characterLevel >= 5) diceCount = baseCount * 2; if (characterLevel >= 11) diceCount = baseCount * 3; if (characterLevel >= 17) diceCount = baseCount * 4; return `${diceCount}`; } /** * Calculate upcast damage dice */ export function calculateUpcastDice(spell: Spell, slotLevel: number): string { const effect = spell.effects.find(e => e.dice); if (!effect?.dice) return ''; const baseDice = effect.dice; const upcastBonus = effect.upcastBonus; if (!upcastBonus || slotLevel <= spell.level) { return baseDice; } const levelsAbove = slotLevel - spell.level; const bonusLevels = Math.floor(levelsAbove / upcastBonus.perLevel); // Parse base dice (e.g., "8d6" -> {count: 8, size: 6}) const baseDiceMatch = baseDice.match(/(\d+)d(\d+)/); const bonusDiceMatch = upcastBonus.dice.match(/(\d+)d(\d+)/); if (!baseDiceMatch) return baseDice; let totalCount = parseInt(baseDiceMatch[1]); const diceSize = baseDiceMatch[2]; if (bonusDiceMatch) { totalCount += parseInt(bonusDiceMatch[1]) * bonusLevels; } // Handle modifiers (e.g., "3d4+3") const modMatch = baseDice.match(/([+-]\d+)$/); const modifier = modMatch ? modMatch[1] : ''; return `${totalCount}d${diceSize}${modifier}`; } // Export total spell count for tests export const SPELL_COUNT = SPELL_DATABASE.size;

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