Files
claudecode 85adbbf084 Phase 6 — NPC tracker
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 18:13:38 -04:00

265 lines
8.7 KiB
JavaScript

const path = require('path');
const Database = require('better-sqlite3');
const db = new Database(path.join(__dirname, '..', 'data', 'mythic-oracle.db'));
db.pragma('foreign_keys = ON');
db.exec(`
CREATE TABLE IF NOT EXISTS systems (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS campaigns (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
system_id INTEGER NOT NULL REFERENCES systems(id),
chaos_factor INTEGER NOT NULL DEFAULT 5,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS threads (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL REFERENCES campaigns(id),
title TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
notes TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
related_npcs TEXT,
related_location TEXT,
origin TEXT,
stakes TEXT,
last_development TEXT,
next_beat TEXT,
suspected_resolution TEXT
);
CREATE TABLE IF NOT EXISTS npcs (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL REFERENCES campaigns(id),
name TEXT NOT NULL,
description TEXT,
notes TEXT,
motivations TEXT,
appearance TEXT,
age TEXT,
gender TEXT,
pronouns TEXT,
voice TEXT,
distinguishing_features TEXT,
faction TEXT,
occupation TEXT,
social_status TEXT,
relationship_to_pc TEXT,
loyalty TEXT,
personality_traits TEXT,
fears TEXT,
desires TEXT,
secrets TEXT,
first_encountered TEXT,
last_seen TEXT,
current_location TEXT,
current_goal TEXT,
role_in_threads TEXT,
alive_status TEXT DEFAULT 'alive',
disposition TEXT DEFAULT 'unknown',
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS session_logs (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL REFERENCES campaigns(id),
title TEXT,
content TEXT,
session_date TEXT NOT NULL DEFAULT (date('now')),
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS campaign_docs (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL REFERENCES campaigns(id),
doc_type TEXT NOT NULL,
content TEXT,
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE (campaign_id, doc_type)
);
CREATE TABLE IF NOT EXISTS custom_tables (
id INTEGER PRIMARY KEY,
campaign_id INTEGER REFERENCES campaigns(id),
name TEXT NOT NULL,
description TEXT,
entries TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS characters_dnd5e (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT, class TEXT, level INTEGER DEFAULT 1,
background TEXT, race TEXT, alignment TEXT,
str INTEGER, dex INTEGER, con INTEGER,
int_score INTEGER, wis INTEGER, cha INTEGER,
hp_max INTEGER, hp_current INTEGER, hp_temp INTEGER,
ac INTEGER, speed INTEGER,
proficiency INTEGER DEFAULT 2,
inspiration INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS characters_morkborg (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT, class TEXT,
str INTEGER, agi INTEGER, pre INTEGER, tou INTEGER,
hp_max INTEGER, hp_current INTEGER,
omens_max INTEGER, omens_current INTEGER,
silver INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS characters_cairn (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT, background TEXT,
str INTEGER, dex INTEGER, wil INTEGER,
hp_max INTEGER, hp_current INTEGER,
armor INTEGER DEFAULT 0,
deprived INTEGER DEFAULT 0,
gold INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS cairn_inventory (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters_cairn(id),
slot INTEGER,
name TEXT NOT NULL,
description TEXT,
is_bulky INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS characters_chaalt (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT, class TEXT, level INTEGER DEFAULT 1, race TEXT,
str INTEGER, dex INTEGER, con INTEGER,
int_score INTEGER, wis INTEGER, cha INTEGER,
hp_max INTEGER, hp_current INTEGER,
ac INTEGER, thac0 INTEGER,
gold INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS characters_ironsworn (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT,
edge INTEGER DEFAULT 1, heart INTEGER DEFAULT 1,
iron INTEGER DEFAULT 1, shadow INTEGER DEFAULT 1,
wits INTEGER DEFAULT 1,
health INTEGER DEFAULT 5, spirit INTEGER DEFAULT 5,
supply INTEGER DEFAULT 5,
momentum INTEGER DEFAULT 2, momentum_reset INTEGER DEFAULT 2,
momentum_max INTEGER DEFAULT 10,
wounded INTEGER DEFAULT 0, shaken INTEGER DEFAULT 0,
unprepared INTEGER DEFAULT 0, encumbered INTEGER DEFAULT 0,
maimed INTEGER DEFAULT 0, corrupted INTEGER DEFAULT 0,
cursed INTEGER DEFAULT 0, tormented INTEGER DEFAULT 0,
experience INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS ironsworn_assets (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters_ironsworn(id),
name TEXT NOT NULL,
asset_type TEXT,
ability_1 TEXT, ability_1_checked INTEGER DEFAULT 0,
ability_2 TEXT, ability_2_checked INTEGER DEFAULT 0,
ability_3 TEXT, ability_3_checked INTEGER DEFAULT 0,
notes TEXT
);
CREATE TABLE IF NOT EXISTS ironsworn_vows (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL REFERENCES campaigns(id),
title TEXT NOT NULL,
rank TEXT NOT NULL,
progress INTEGER DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active',
notes TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS characters_shadowrun (
id INTEGER PRIMARY KEY,
campaign_id INTEGER NOT NULL UNIQUE REFERENCES campaigns(id),
name TEXT, metatype TEXT, archetype TEXT,
gender TEXT, age INTEGER,
body INTEGER, agility INTEGER, reaction INTEGER,
strength INTEGER, willpower INTEGER, logic INTEGER,
intuition INTEGER, charisma INTEGER,
essence REAL DEFAULT 6.0,
edge INTEGER, edge_current INTEGER,
magic_resonance INTEGER,
nuyen INTEGER DEFAULT 0,
karma INTEGER DEFAULT 0, total_karma INTEGER DEFAULT 0,
street_cred INTEGER DEFAULT 0,
notoriety INTEGER DEFAULT 0, reputation INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS shadowrun_skills (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters_shadowrun(id),
name TEXT NOT NULL,
rating INTEGER DEFAULT 0,
specialization TEXT,
linked_attr TEXT
);
CREATE TABLE IF NOT EXISTS shadowrun_contacts (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters_shadowrun(id),
name TEXT NOT NULL,
loyalty INTEGER,
connection INTEGER,
notes TEXT
);
CREATE TABLE IF NOT EXISTS shadowrun_qualities (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters_shadowrun(id),
name TEXT NOT NULL,
quality_type TEXT NOT NULL,
karma_cost INTEGER,
description TEXT
);
`);
const systemCount = db.prepare('SELECT COUNT(*) AS count FROM systems').get().count;
if (systemCount === 0) {
const insertSystem = db.prepare('INSERT INTO systems (name, slug) VALUES (?, ?)');
const seedSystems = db.transaction((systems) => {
for (const system of systems) {
insertSystem.run(system.name, system.slug);
}
});
seedSystems([
{ name: 'D&D 5e', slug: 'dnd5e' },
{ name: 'Mork Borg', slug: 'morkborg' },
{ name: 'Cairn', slug: 'cairn' },
{ name: "Cha'alt", slug: 'chaalt' },
{ name: 'Ironsworn', slug: 'ironsworn' },
{ name: 'Shadowrun', slug: 'shadowrun' },
]);
}
module.exports = db;