Skip to main content
Glama
creature-presets.ts34.5 kB
/** * D&D 5e SRD Creature Presets * * Provides pre-configured creature stat blocks for common monsters. * These reduce token overhead by ~90% compared to manual specification. * * Usage: * getCreaturePreset('goblin') -> full stat block * expandCreatureTemplate('goblin:archer') -> goblin with shortbow * * Template syntax: "creature" or "creature:variant" */ /** * Partial character data for presets - id, createdAt, updatedAt generated on use */ export interface CreaturePreset { name: string; stats: { str: number; dex: number; con: number; int: number; wis: number; cha: number }; hp: number; maxHp: number; ac: number; level: number; characterType: 'enemy' | 'npc'; race?: string; characterClass?: string; // Combat modifiers resistances?: string[]; vulnerabilities?: string[]; immunities?: string[]; // Default attack info (for reference - actual attacks go in items) defaultAttack?: { name: string; damage: string; // e.g., "1d6+2" damageType: string; toHit?: number; }; // Movement and size size?: 'tiny' | 'small' | 'medium' | 'large' | 'huge' | 'gargantuan'; speed?: number; // Skill bonuses perceptionBonus?: number; stealthBonus?: number; // Challenge rating (for XP calculation) cr?: number; xpValue?: number; // Special traits description traits?: string[]; } /** * Creature variant modifiers */ interface CreatureVariant { namePrefix?: string; nameSuffix?: string; hpModifier?: number; acModifier?: number; statModifiers?: Partial<{ str: number; dex: number; con: number; int: number; wis: number; cha: number }>; defaultAttack?: CreaturePreset['defaultAttack']; equipment?: string[]; // Item preset names to equip } // ═══════════════════════════════════════════════════════════════════════════ // BASE CREATURE PRESETS - D&D 5e SRD // ═══════════════════════════════════════════════════════════════════════════ export const CREATURE_PRESETS: Record<string, CreaturePreset> = { // ───────────────────────────────────────────────────────────────────────── // HUMANOIDS - Low CR // ───────────────────────────────────────────────────────────────────────── goblin: { name: 'Goblin', stats: { str: 8, dex: 14, con: 10, int: 10, wis: 8, cha: 8 }, hp: 7, maxHp: 7, ac: 15, // Leather armor + shield level: 1, characterType: 'enemy', race: 'Goblin', size: 'small', speed: 30, stealthBonus: 6, cr: 0.25, xpValue: 50, defaultAttack: { name: 'Scimitar', damage: '1d6+2', damageType: 'slashing', toHit: 4 }, traits: ['Nimble Escape: Disengage or Hide as bonus action'] }, hobgoblin: { name: 'Hobgoblin', stats: { str: 13, dex: 12, con: 12, int: 10, wis: 10, cha: 9 }, hp: 11, maxHp: 11, ac: 18, // Chain mail + shield level: 1, characterType: 'enemy', race: 'Hobgoblin', size: 'medium', speed: 30, cr: 0.5, xpValue: 100, defaultAttack: { name: 'Longsword', damage: '1d8+1', damageType: 'slashing', toHit: 3 }, traits: ['Martial Advantage: Extra 2d6 damage once per turn if ally is within 5 ft of target'] }, bugbear: { name: 'Bugbear', stats: { str: 15, dex: 14, con: 13, int: 8, wis: 11, cha: 9 }, hp: 27, maxHp: 27, ac: 16, // Hide armor + shield level: 3, characterType: 'enemy', race: 'Bugbear', size: 'medium', speed: 30, stealthBonus: 6, perceptionBonus: 2, cr: 1, xpValue: 200, defaultAttack: { name: 'Morningstar', damage: '2d8+2', damageType: 'piercing', toHit: 4 }, traits: ['Surprise Attack: Extra 2d6 damage if creature is surprised', 'Brute: Extra damage die on melee hits'] }, orc: { name: 'Orc', stats: { str: 16, dex: 12, con: 16, int: 7, wis: 11, cha: 10 }, hp: 15, maxHp: 15, ac: 13, // Hide armor level: 1, characterType: 'enemy', race: 'Orc', size: 'medium', speed: 30, cr: 0.5, xpValue: 100, defaultAttack: { name: 'Greataxe', damage: '1d12+3', damageType: 'slashing', toHit: 5 }, traits: ['Aggressive: Bonus action to move up to speed toward hostile creature'] }, bandit: { name: 'Bandit', stats: { str: 11, dex: 12, con: 12, int: 10, wis: 10, cha: 10 }, hp: 11, maxHp: 11, ac: 12, // Leather armor level: 1, characterType: 'enemy', race: 'Human', characterClass: 'rogue', size: 'medium', speed: 30, cr: 0.125, xpValue: 25, defaultAttack: { name: 'Scimitar', damage: '1d6+1', damageType: 'slashing', toHit: 3 } }, bandit_captain: { name: 'Bandit Captain', stats: { str: 15, dex: 16, con: 14, int: 14, wis: 11, cha: 14 }, hp: 65, maxHp: 65, ac: 15, // Studded leather level: 5, characterType: 'enemy', race: 'Human', characterClass: 'fighter', size: 'medium', speed: 30, cr: 2, xpValue: 450, defaultAttack: { name: 'Scimitar', damage: '1d6+3', damageType: 'slashing', toHit: 5 }, traits: ['Multiattack: Three melee attacks or two ranged'] }, thug: { name: 'Thug', stats: { str: 15, dex: 11, con: 14, int: 10, wis: 10, cha: 11 }, hp: 32, maxHp: 32, ac: 11, // Leather armor level: 2, characterType: 'enemy', race: 'Human', size: 'medium', speed: 30, cr: 0.5, xpValue: 100, defaultAttack: { name: 'Mace', damage: '1d6+2', damageType: 'bludgeoning', toHit: 4 }, traits: ['Pack Tactics: Advantage when ally is within 5 ft of target'] }, cultist: { name: 'Cultist', stats: { str: 11, dex: 12, con: 10, int: 10, wis: 11, cha: 10 }, hp: 9, maxHp: 9, ac: 12, // Leather armor level: 1, characterType: 'enemy', race: 'Human', size: 'medium', speed: 30, cr: 0.125, xpValue: 25, defaultAttack: { name: 'Scimitar', damage: '1d6+1', damageType: 'slashing', toHit: 3 }, traits: ['Dark Devotion: Advantage on saves vs charmed/frightened'] }, // ───────────────────────────────────────────────────────────────────────── // UNDEAD // ───────────────────────────────────────────────────────────────────────── skeleton: { name: 'Skeleton', stats: { str: 10, dex: 14, con: 15, int: 6, wis: 8, cha: 5 }, hp: 13, maxHp: 13, ac: 13, // Armor scraps level: 1, characterType: 'enemy', race: 'Undead', size: 'medium', speed: 30, vulnerabilities: ['bludgeoning'], immunities: ['poison'], cr: 0.25, xpValue: 50, defaultAttack: { name: 'Shortsword', damage: '1d6+2', damageType: 'piercing', toHit: 4 } }, zombie: { name: 'Zombie', stats: { str: 13, dex: 6, con: 16, int: 3, wis: 6, cha: 5 }, hp: 22, maxHp: 22, ac: 8, level: 1, characterType: 'enemy', race: 'Undead', size: 'medium', speed: 20, immunities: ['poison'], cr: 0.25, xpValue: 50, defaultAttack: { name: 'Slam', damage: '1d6+1', damageType: 'bludgeoning', toHit: 3 }, traits: ['Undead Fortitude: DC 5 + damage CON save to stay at 1 HP instead of 0'] }, ghoul: { name: 'Ghoul', stats: { str: 13, dex: 15, con: 10, int: 7, wis: 10, cha: 6 }, hp: 22, maxHp: 22, ac: 12, level: 2, characterType: 'enemy', race: 'Undead', size: 'medium', speed: 30, immunities: ['poison'], cr: 1, xpValue: 200, defaultAttack: { name: 'Claws', damage: '2d4+2', damageType: 'slashing', toHit: 4 }, traits: ['Paralyzing Touch: DC 10 CON save or paralyzed for 1 minute'] }, wight: { name: 'Wight', stats: { str: 15, dex: 14, con: 16, int: 10, wis: 13, cha: 15 }, hp: 45, maxHp: 45, ac: 14, // Studded leather level: 4, characterType: 'enemy', race: 'Undead', size: 'medium', speed: 30, resistances: ['necrotic', 'nonmagical bludgeoning/piercing/slashing'], immunities: ['poison'], cr: 3, xpValue: 700, defaultAttack: { name: 'Longsword', damage: '1d8+2', damageType: 'slashing', toHit: 4 }, traits: ['Life Drain: Necrotic attack reduces max HP', 'Sunlight Sensitivity: Disadvantage in sunlight'] }, // ───────────────────────────────────────────────────────────────────────── // BEASTS // ───────────────────────────────────────────────────────────────────────── wolf: { name: 'Wolf', stats: { str: 12, dex: 15, con: 12, int: 3, wis: 12, cha: 6 }, hp: 11, maxHp: 11, ac: 13, // Natural armor level: 1, characterType: 'enemy', race: 'Beast', size: 'medium', speed: 40, perceptionBonus: 3, stealthBonus: 4, cr: 0.25, xpValue: 50, defaultAttack: { name: 'Bite', damage: '2d4+2', damageType: 'piercing', toHit: 4 }, traits: ['Pack Tactics: Advantage when ally within 5 ft', 'Keen Hearing and Smell: Advantage on Perception'] }, dire_wolf: { name: 'Dire Wolf', stats: { str: 17, dex: 15, con: 15, int: 3, wis: 12, cha: 7 }, hp: 37, maxHp: 37, ac: 14, level: 3, characterType: 'enemy', race: 'Beast', size: 'large', speed: 50, perceptionBonus: 3, stealthBonus: 4, cr: 1, xpValue: 200, defaultAttack: { name: 'Bite', damage: '2d6+3', damageType: 'piercing', toHit: 5 }, traits: ['Pack Tactics', 'Keen Hearing and Smell', 'Knockdown: DC 13 STR or prone'] }, giant_spider: { name: 'Giant Spider', stats: { str: 14, dex: 16, con: 12, int: 2, wis: 11, cha: 4 }, hp: 26, maxHp: 26, ac: 14, level: 2, characterType: 'enemy', race: 'Beast', size: 'large', speed: 30, stealthBonus: 7, cr: 1, xpValue: 200, defaultAttack: { name: 'Bite', damage: '1d8+3', damageType: 'piercing', toHit: 5 }, traits: ['Spider Climb', 'Web Sense', 'Web Walker', 'Poison: DC 11 CON or 2d8 poison damage'] }, giant_rat: { name: 'Giant Rat', stats: { str: 7, dex: 15, con: 11, int: 2, wis: 10, cha: 4 }, hp: 7, maxHp: 7, ac: 12, level: 1, characterType: 'enemy', race: 'Beast', size: 'small', speed: 30, cr: 0.125, xpValue: 25, defaultAttack: { name: 'Bite', damage: '1d4+2', damageType: 'piercing', toHit: 4 }, traits: ['Pack Tactics', 'Keen Smell'] }, bear_black: { name: 'Black Bear', stats: { str: 15, dex: 10, con: 14, int: 2, wis: 12, cha: 7 }, hp: 19, maxHp: 19, ac: 11, level: 2, characterType: 'enemy', race: 'Beast', size: 'medium', speed: 40, perceptionBonus: 3, cr: 0.5, xpValue: 100, defaultAttack: { name: 'Claws', damage: '2d4+2', damageType: 'slashing', toHit: 4 }, traits: ['Multiattack: Bite and claws', 'Keen Smell'] }, bear_brown: { name: 'Brown Bear', stats: { str: 19, dex: 10, con: 16, int: 2, wis: 13, cha: 7 }, hp: 34, maxHp: 34, ac: 11, level: 3, characterType: 'enemy', race: 'Beast', size: 'large', speed: 40, perceptionBonus: 3, cr: 1, xpValue: 200, defaultAttack: { name: 'Claws', damage: '2d6+4', damageType: 'slashing', toHit: 6 }, traits: ['Multiattack: Bite and claws', 'Keen Smell'] }, // ───────────────────────────────────────────────────────────────────────── // DRAGONS (Wyrmlings) // ───────────────────────────────────────────────────────────────────────── dragon_wyrmling_red: { name: 'Red Dragon Wyrmling', stats: { str: 19, dex: 10, con: 17, int: 12, wis: 11, cha: 15 }, hp: 75, maxHp: 75, ac: 17, level: 6, characterType: 'enemy', race: 'Dragon', size: 'medium', speed: 30, immunities: ['fire'], perceptionBonus: 4, stealthBonus: 2, cr: 4, xpValue: 1100, defaultAttack: { name: 'Bite', damage: '1d10+4', damageType: 'piercing', toHit: 6 }, traits: ['Fire Breath: 15 ft cone, 7d6 fire, DC 13 DEX half'] }, dragon_wyrmling_white: { name: 'White Dragon Wyrmling', stats: { str: 14, dex: 10, con: 14, int: 5, wis: 10, cha: 11 }, hp: 32, maxHp: 32, ac: 16, level: 4, characterType: 'enemy', race: 'Dragon', size: 'medium', speed: 30, immunities: ['cold'], perceptionBonus: 4, stealthBonus: 2, cr: 2, xpValue: 450, defaultAttack: { name: 'Bite', damage: '1d10+2', damageType: 'piercing', toHit: 4 }, traits: ['Cold Breath: 15 ft cone, 5d8 cold, DC 12 CON half'] }, // ───────────────────────────────────────────────────────────────────────── // CONSTRUCTS // ───────────────────────────────────────────────────────────────────────── animated_armor: { name: 'Animated Armor', stats: { str: 14, dex: 11, con: 13, int: 1, wis: 3, cha: 1 }, hp: 33, maxHp: 33, ac: 18, // Natural armor level: 3, characterType: 'enemy', race: 'Construct', size: 'medium', speed: 25, immunities: ['poison', 'psychic'], cr: 1, xpValue: 200, defaultAttack: { name: 'Slam', damage: '1d6+2', damageType: 'bludgeoning', toHit: 4 }, traits: ['Antimagic Susceptibility: Incapacitated in antimagic', 'False Appearance: Looks like normal armor'] }, flying_sword: { name: 'Flying Sword', stats: { str: 12, dex: 15, con: 11, int: 1, wis: 5, cha: 1 }, hp: 17, maxHp: 17, ac: 17, // Natural armor level: 1, characterType: 'enemy', race: 'Construct', size: 'small', speed: 50, immunities: ['poison', 'psychic'], cr: 0.25, xpValue: 50, defaultAttack: { name: 'Longsword', damage: '1d8+1', damageType: 'slashing', toHit: 3 }, traits: ['Antimagic Susceptibility', 'False Appearance'] }, // ───────────────────────────────────────────────────────────────────────── // MONSTROSITIES // ───────────────────────────────────────────────────────────────────────── mimic: { name: 'Mimic', stats: { str: 17, dex: 12, con: 15, int: 5, wis: 13, cha: 8 }, hp: 58, maxHp: 58, ac: 12, level: 4, characterType: 'enemy', race: 'Monstrosity', size: 'medium', speed: 15, immunities: ['acid'], stealthBonus: 5, cr: 2, xpValue: 450, defaultAttack: { name: 'Pseudopod', damage: '1d8+3', damageType: 'bludgeoning', toHit: 5 }, traits: ['Shapechanger: Polymorph into object', 'Adhesive: Grapples on hit', 'False Appearance', 'Grappler'] }, owlbear: { name: 'Owlbear', stats: { str: 20, dex: 12, con: 17, int: 3, wis: 12, cha: 7 }, hp: 59, maxHp: 59, ac: 13, level: 5, characterType: 'enemy', race: 'Monstrosity', size: 'large', speed: 40, perceptionBonus: 3, cr: 3, xpValue: 700, defaultAttack: { name: 'Claws', damage: '2d8+5', damageType: 'slashing', toHit: 7 }, traits: ['Multiattack: Beak and claws', 'Keen Sight and Smell'] }, harpy: { name: 'Harpy', stats: { str: 12, dex: 13, con: 12, int: 7, wis: 10, cha: 13 }, hp: 38, maxHp: 38, ac: 11, level: 3, characterType: 'enemy', race: 'Monstrosity', size: 'medium', speed: 20, cr: 1, xpValue: 200, defaultAttack: { name: 'Claws', damage: '2d4+1', damageType: 'slashing', toHit: 3 }, traits: ['Multiattack: Claws and club', 'Luring Song: DC 11 WIS or charmed'] }, // ───────────────────────────────────────────────────────────────────────── // DEMONS & FIENDS // ───────────────────────────────────────────────────────────────────────── imp: { name: 'Imp', stats: { str: 6, dex: 17, con: 13, int: 11, wis: 12, cha: 14 }, hp: 10, maxHp: 10, ac: 13, level: 2, characterType: 'enemy', race: 'Fiend', size: 'tiny', speed: 20, resistances: ['cold', 'nonmagical bludgeoning/piercing/slashing'], immunities: ['fire', 'poison'], stealthBonus: 5, cr: 1, xpValue: 200, defaultAttack: { name: 'Sting', damage: '1d4+3', damageType: 'piercing', toHit: 5 }, traits: ['Shapechanger', 'Devils Sight', 'Magic Resistance', 'Poison Sting: DC 11 CON or 3d6 poison'] }, quasit: { name: 'Quasit', stats: { str: 5, dex: 17, con: 10, int: 7, wis: 10, cha: 10 }, hp: 7, maxHp: 7, ac: 13, level: 2, characterType: 'enemy', race: 'Fiend', size: 'tiny', speed: 40, resistances: ['cold', 'fire', 'lightning', 'nonmagical bludgeoning/piercing/slashing'], immunities: ['poison'], stealthBonus: 5, cr: 1, xpValue: 200, defaultAttack: { name: 'Claws', damage: '1d4+3', damageType: 'slashing', toHit: 5 }, traits: ['Shapechanger', 'Magic Resistance', 'Poison Claws: DC 10 CON or 2d4 poison'] }, // ───────────────────────────────────────────────────────────────────────── // GIANTS // ───────────────────────────────────────────────────────────────────────── ogre: { name: 'Ogre', stats: { str: 19, dex: 8, con: 16, int: 5, wis: 7, cha: 7 }, hp: 59, maxHp: 59, ac: 11, // Hide armor level: 4, characterType: 'enemy', race: 'Giant', size: 'large', speed: 40, cr: 2, xpValue: 450, defaultAttack: { name: 'Greatclub', damage: '2d8+4', damageType: 'bludgeoning', toHit: 6 } }, troll: { name: 'Troll', stats: { str: 18, dex: 13, con: 20, int: 7, wis: 9, cha: 7 }, hp: 84, maxHp: 84, ac: 15, level: 6, characterType: 'enemy', race: 'Giant', size: 'large', speed: 30, perceptionBonus: 2, cr: 5, xpValue: 1800, defaultAttack: { name: 'Claws', damage: '2d6+4', damageType: 'slashing', toHit: 7 }, traits: ['Multiattack: Bite and 2 claws', 'Regeneration: 10 HP per turn unless fire/acid damage', 'Keen Smell'] }, // ───────────────────────────────────────────────────────────────────────── // ELEMENTALS // ───────────────────────────────────────────────────────────────────────── fire_elemental: { name: 'Fire Elemental', stats: { str: 10, dex: 17, con: 16, int: 6, wis: 10, cha: 7 }, hp: 102, maxHp: 102, ac: 13, level: 8, characterType: 'enemy', race: 'Elemental', size: 'large', speed: 50, resistances: ['nonmagical bludgeoning/piercing/slashing'], immunities: ['fire', 'poison'], cr: 5, xpValue: 1800, defaultAttack: { name: 'Touch', damage: '2d6+3', damageType: 'fire', toHit: 6 }, traits: ['Fire Form: Move through 1-inch spaces', 'Illumination: Bright light 30 ft', 'Water Susceptibility: 1 cold damage per gallon'] }, water_elemental: { name: 'Water Elemental', stats: { str: 18, dex: 14, con: 18, int: 5, wis: 10, cha: 8 }, hp: 114, maxHp: 114, ac: 14, level: 8, characterType: 'enemy', race: 'Elemental', size: 'large', speed: 30, resistances: ['acid', 'nonmagical bludgeoning/piercing/slashing'], immunities: ['poison'], cr: 5, xpValue: 1800, defaultAttack: { name: 'Slam', damage: '2d8+4', damageType: 'bludgeoning', toHit: 7 }, traits: ['Water Form: Move through 1-inch spaces', 'Freeze: 1 cold damage freezes 1 ft', 'Whelm: Engulf and drown'] }, }; // ═══════════════════════════════════════════════════════════════════════════ // CREATURE VARIANTS // ═══════════════════════════════════════════════════════════════════════════ export const CREATURE_VARIANTS: Record<string, Record<string, CreatureVariant>> = { goblin: { warrior: { nameSuffix: ' Warrior', hpModifier: 3, acModifier: 0, equipment: ['scimitar', 'shield'] }, archer: { nameSuffix: ' Archer', hpModifier: 0, acModifier: -2, // No shield defaultAttack: { name: 'Shortbow', damage: '1d6+2', damageType: 'piercing', toHit: 4 }, equipment: ['shortbow'] }, boss: { namePrefix: 'Goblin ', nameSuffix: ' Boss', hpModifier: 15, acModifier: 2, statModifiers: { str: 2, con: 2, cha: 4 }, equipment: ['scimitar', 'shield'] }, shaman: { nameSuffix: ' Shaman', hpModifier: 5, acModifier: -3, // No armor statModifiers: { wis: 4, cha: 2 }, equipment: ['quarterstaff'] } }, skeleton: { warrior: { nameSuffix: ' Warrior', hpModifier: 5, acModifier: 2, equipment: ['shortsword', 'shield'] }, archer: { nameSuffix: ' Archer', hpModifier: 0, defaultAttack: { name: 'Shortbow', damage: '1d6+2', damageType: 'piercing', toHit: 4 }, equipment: ['shortbow'] }, mage: { nameSuffix: ' Mage', hpModifier: 10, statModifiers: { int: 6, wis: 4 } } }, orc: { warrior: { nameSuffix: ' Warrior', hpModifier: 5, equipment: ['greataxe'] }, berserker: { nameSuffix: ' Berserker', hpModifier: 10, acModifier: -2, statModifiers: { str: 2, con: 2 }, equipment: ['greataxe'] }, warleader: { namePrefix: 'Orc ', nameSuffix: ' War Chief', hpModifier: 30, acModifier: 3, statModifiers: { str: 4, con: 4, cha: 4 }, equipment: ['greataxe', 'chainmail'] } }, bandit: { thug: { nameSuffix: ' Thug', hpModifier: 10, statModifiers: { str: 2 }, equipment: ['mace'] }, archer: { nameSuffix: ' Archer', hpModifier: 0, defaultAttack: { name: 'Light Crossbow', damage: '1d8+1', damageType: 'piercing', toHit: 3 }, equipment: ['light_crossbow'] } }, hobgoblin: { warrior: { nameSuffix: ' Warrior', hpModifier: 5, equipment: ['longsword', 'shield', 'chainmail'] }, captain: { namePrefix: 'Hobgoblin ', nameSuffix: ' Captain', hpModifier: 30, acModifier: 2, statModifiers: { str: 2, con: 2, cha: 4 }, equipment: ['longsword', 'shield', 'chainmail'] }, archer: { nameSuffix: ' Archer', hpModifier: 0, acModifier: -4, defaultAttack: { name: 'Longbow', damage: '1d8+1', damageType: 'piercing', toHit: 3 }, equipment: ['longbow'] } }, zombie: { fast: { namePrefix: 'Fast ', hpModifier: -5, statModifiers: { dex: 6 } }, brute: { nameSuffix: ' Brute', hpModifier: 15, acModifier: 2, statModifiers: { str: 4, con: 4 } } }, wolf: { alpha: { namePrefix: 'Alpha ', hpModifier: 10, acModifier: 1, statModifiers: { str: 2, con: 2, cha: 4 } }, dire: { namePrefix: 'Dire ', hpModifier: 26, acModifier: 1, statModifiers: { str: 5, con: 3 } } } }; // ═══════════════════════════════════════════════════════════════════════════ // HELPER FUNCTIONS // ═══════════════════════════════════════════════════════════════════════════ /** * Get a raw creature preset by name */ export function getCreaturePreset(name: string): CreaturePreset | null { const normalized = name.toLowerCase().replace(/[\s-]/g, '_'); return CREATURE_PRESETS[normalized] || null; } /** * Parse a creature template string like "goblin:archer" or just "goblin" */ export function parseCreatureTemplate(template: string): { base: string; variant?: string } { const [base, variant] = template.toLowerCase().split(':'); return { base: base.replace(/[\s-]/g, '_'), variant }; } /** * Expand a creature template into a full preset with variant applied */ export function expandCreatureTemplate(template: string, nameOverride?: string): CreaturePreset | null { const { base, variant } = parseCreatureTemplate(template); const basePreset = getCreaturePreset(base); if (!basePreset) { return null; } // No variant - return base if (!variant) { if (nameOverride) { return { ...basePreset, name: nameOverride }; } return { ...basePreset }; } // Find variant const variantDef = CREATURE_VARIANTS[base]?.[variant]; if (!variantDef) { // Variant not found, return base with warning in name console.warn(`Unknown variant "${variant}" for "${base}", using base preset`); if (nameOverride) { return { ...basePreset, name: nameOverride }; } return { ...basePreset }; } // Apply variant modifications const expanded: CreaturePreset = { ...basePreset, name: nameOverride || `${variantDef.namePrefix || ''}${basePreset.name}${variantDef.nameSuffix || ''}`, hp: basePreset.hp + (variantDef.hpModifier || 0), maxHp: basePreset.maxHp + (variantDef.hpModifier || 0), ac: basePreset.ac + (variantDef.acModifier || 0), }; // Apply stat modifiers if (variantDef.statModifiers) { expanded.stats = { str: basePreset.stats.str + (variantDef.statModifiers.str || 0), dex: basePreset.stats.dex + (variantDef.statModifiers.dex || 0), con: basePreset.stats.con + (variantDef.statModifiers.con || 0), int: basePreset.stats.int + (variantDef.statModifiers.int || 0), wis: basePreset.stats.wis + (variantDef.statModifiers.wis || 0), cha: basePreset.stats.cha + (variantDef.statModifiers.cha || 0), }; } // Override default attack if specified if (variantDef.defaultAttack) { expanded.defaultAttack = variantDef.defaultAttack; } return expanded; } /** * List all available creature presets */ export function listCreaturePresets(): string[] { return Object.keys(CREATURE_PRESETS); } /** * List all variants for a creature */ export function listCreatureVariants(creatureName: string): string[] { const normalized = creatureName.toLowerCase().replace(/[\s-]/g, '_'); const variants = CREATURE_VARIANTS[normalized]; return variants ? Object.keys(variants) : []; } /** * Get all available templates (base and variants) as strings */ export function listAllTemplates(): string[] { const templates: string[] = []; for (const base of Object.keys(CREATURE_PRESETS)) { templates.push(base); const variants = CREATURE_VARIANTS[base]; if (variants) { for (const variant of Object.keys(variants)) { templates.push(`${base}:${variant}`); } } } return templates; }

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