import type { ResultSetHeader, RowDataPacket } from "mysql2"; import db from "./db.js"; const SPELLS = [ // PRIEST TIER 1 { name: "Cure Wounds", class: "priest", tier: 1, casting_stat: "WIS", duration: "Instant", range: "Close", is_focus: 0, description: "Touch restores HP. Roll 1d6 + half your level (round down); target regains that many HP." }, { name: "Holy Weapon", class: "priest", tier: 1, casting_stat: "WIS", duration: "5 rounds", range: "Close", is_focus: 0, description: "One weapon touched becomes magical, gaining +1 to attack and damage." }, { name: "Light", class: "both", tier: 1, casting_stat: "WIS", duration: "1 hour", range: "Close", is_focus: 0, description: "One object touched glows, illuminating to near distance." }, { name: "Protection From Evil", class: "both", tier: 1, casting_stat: "WIS", duration: "5 rounds", range: "Self", is_focus: 0, description: "Chaotic beings have disadvantage on attacks and spellcasting against you. They cannot possess, compel, or beguile you." }, { name: "Shield of Faith", class: "priest", tier: 1, casting_stat: "WIS", duration: "Focus", range: "Close", is_focus: 1, description: "Gain +2 bonus to AC for as long as you focus." }, { name: "Turn Undead", class: "priest", tier: 1, casting_stat: "WIS", duration: "Instant", range: "Near", is_focus: 0, description: "Rebuke undead within near. They make a CHA check vs your spellcasting check. Fail by 10+ and level <= yours: destroyed. Fail: flees for 5 rounds." }, // PRIEST TIER 2 { name: "Augury", class: "priest", tier: 2, casting_stat: "WIS", duration: "Instant", range: "Self", is_focus: 0, description: "Ask the GM one question about a specific course of action. The GM says weal (good outcome) or woe (bad outcome)." }, { name: "Bless", class: "priest", tier: 2, casting_stat: "WIS", duration: "Instant", range: "Close", is_focus: 0, description: "One creature touched gains a luck token." }, { name: "Blind/Deafen", class: "priest", tier: 2, casting_stat: "WIS", duration: "Focus", range: "Near", is_focus: 1, description: "One creature loses one sense. It has disadvantage on tasks requiring that sense." }, { name: "Cleansing Weapon", class: "priest", tier: 2, casting_stat: "WIS", duration: "5 rounds", range: "Close", is_focus: 0, description: "One weapon deals +1d4 damage (1d6 vs undead), wreathed in purifying flames." }, { name: "Smite", class: "priest", tier: 2, casting_stat: "WIS", duration: "Instant", range: "Near", is_focus: 0, description: "Call down punishing flames on one creature, dealing 1d6 damage." }, { name: "Zone of Truth", class: "priest", tier: 2, casting_stat: "WIS", duration: "Focus", range: "Near", is_focus: 1, description: "Compel one creature to speak only truth. It cannot utter deliberate lies while in range." }, // WIZARD TIER 1 { name: "Alarm", class: "wizard", tier: 1, casting_stat: "INT", duration: "1 day", range: "Close", is_focus: 0, description: "Touch one object (door, threshold). A bell sounds in your head if an undesignated creature touches or crosses the object." }, { name: "Burning Hands", class: "wizard", tier: 1, casting_stat: "INT", duration: "Instant", range: "Close", is_focus: 0, description: "Spread fingers, unleash a circle of flame filling the close area. Creatures take 1d6 damage; unattended flammable objects ignite." }, { name: "Charm Person", class: "wizard", tier: 1, casting_stat: "INT", duration: "1d8 days", range: "Near", is_focus: 0, description: "Beguile one humanoid of level 2 or less; it regards you as a friend. Ends if you or your allies hurt it. Target knows it was enchanted after." }, { name: "Detect Magic", class: "wizard", tier: 1, casting_stat: "INT", duration: "Focus", range: "Near", is_focus: 1, description: "Sense presence of magic within near range. Focus 2 rounds: discern general properties. Full barriers block this." }, { name: "Feather Fall", class: "wizard", tier: 1, casting_stat: "INT", duration: "Instant", range: "Self", is_focus: 0, description: "Cast when you fall. Slow your descent; land safely on your feet." }, { name: "Floating Disk", class: "wizard", tier: 1, casting_stat: "INT", duration: "10 rounds", range: "Near", is_focus: 0, description: "Create a floating disk carrying up to 20 gear slots at waist height within near. Can not cross drops taller than a human." }, { name: "Hold Portal", class: "wizard", tier: 1, casting_stat: "INT", duration: "10 rounds", range: "Near", is_focus: 0, description: "Magically hold a portal closed. A creature must pass a STR check vs your spellcasting check to open it. Knock ends this." }, { name: "Mage Armor", class: "wizard", tier: 1, casting_stat: "INT", duration: "10 rounds", range: "Self", is_focus: 0, description: "Invisible layer of magical force. Your AC becomes 14 (18 on a critical spellcasting check)." }, { name: "Magic Missile", class: "wizard", tier: 1, casting_stat: "INT", duration: "Instant", range: "Far", is_focus: 0, description: "You have advantage on your check to cast. A glowing bolt of force deals 1d4 damage to one target." }, { name: "Sleep", class: "wizard", tier: 1, casting_stat: "INT", duration: "Instant", range: "Near", is_focus: 0, description: "Weave a lulling spell filling a near-sized cube. Living creatures level 2 or less fall into deep sleep. Vigorous shaking or injury wakes them." }, // WIZARD TIER 2 { name: "Acid Arrow", class: "wizard", tier: 2, casting_stat: "INT", duration: "Focus", range: "Far", is_focus: 1, description: "Conjure a corrosive bolt. One foe takes 1d6 damage per round while you focus." }, { name: "Alter Self", class: "wizard", tier: 2, casting_stat: "INT", duration: "5 rounds", range: "Self", is_focus: 0, description: "Change your physical form, gaining one feature modifying existing anatomy (gills, bear claws, etc.). Cannot grow wings or new limbs." }, { name: "Detect Thoughts", class: "wizard", tier: 2, casting_stat: "INT", duration: "Focus", range: "Near", is_focus: 1, description: "Learn one creature's immediate thoughts each round. Target makes WIS check vs your spellcasting; success means target notices you and spell ends." }, { name: "Fixed Object", class: "wizard", tier: 2, casting_stat: "INT", duration: "5 rounds", range: "Close", is_focus: 0, description: "Object you touch (max 5 lbs) becomes immovable in location. Can support up to 5,000 lbs." }, { name: "Hold Person", class: "wizard", tier: 2, casting_stat: "INT", duration: "Focus", range: "Near", is_focus: 1, description: "Magically paralyze one humanoid creature of level 4 or less." }, { name: "Invisibility", class: "wizard", tier: 2, casting_stat: "INT", duration: "10 rounds", range: "Close", is_focus: 0, description: "Creature touched becomes invisible. Ends if the target attacks or casts a spell." }, { name: "Knock", class: "wizard", tier: 2, casting_stat: "INT", duration: "Instant", range: "Near", is_focus: 0, description: "A door, window, gate, chest, or portal instantly opens. Defeats mundane locks. Creates a loud knock audible to all." }, { name: "Levitate", class: "wizard", tier: 2, casting_stat: "INT", duration: "Focus", range: "Self", is_focus: 1, description: "Float near distance vertically per round. Push against solid objects to move horizontally." }, { name: "Mirror Image", class: "wizard", tier: 2, casting_stat: "INT", duration: "5 rounds", range: "Self", is_focus: 0, description: "Create illusory duplicates equal to half your level (min 1). Each hit destroys one duplicate. Spell ends when all are gone." }, { name: "Misty Step", class: "wizard", tier: 2, casting_stat: "INT", duration: "Instant", range: "Self", is_focus: 0, description: "In a puff of smoke, teleport near distance to an area you can see." }, { name: "Silence", class: "wizard", tier: 2, casting_stat: "INT", duration: "Focus", range: "Far", is_focus: 1, description: "Mute sound in a near-sized cube within range. Creatures inside are deafened and no sounds can be heard from inside." }, { name: "Web", class: "wizard", tier: 2, casting_stat: "INT", duration: "5 rounds", range: "Far", is_focus: 0, description: "Create a near-sized cube of sticky spider web. Creatures are stuck and cannot move; must pass STR check vs your spellcasting to free themselves." }, ] as const; export async function seedSpells(): Promise { const [existing] = await db.execute("SELECT COUNT(*) as c FROM spells"); if ((existing[0] as { c: number }).c > 0) return; for (const spell of SPELLS) { await db.execute( "INSERT INTO spells (name, class, tier, casting_stat, duration, `range`, is_focus, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [spell.name, spell.class, spell.tier, spell.casting_stat, spell.duration, spell.range, spell.is_focus, spell.description] ); } console.log(`Spells seeded: ${SPELLS.length} spells`); }