Files

291 lines
10 KiB
SQL

PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS locations (
id INTEGER PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS dungeons (
id INTEGER PRIMARY KEY,
location_id INTEGER NOT NULL REFERENCES locations(id),
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
recommended_level INTEGER NOT NULL DEFAULT 1,
content_type TEXT NOT NULL DEFAULT 'dungeon' CHECK (content_type IN ('dungeon', 'raid')),
party_size INTEGER NOT NULL DEFAULT 6,
completion_item_level INTEGER,
experience_reward INTEGER NOT NULL DEFAULT 100,
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS difficulties (
id INTEGER PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
dropped_item_level INTEGER NOT NULL,
unlock_level INTEGER NOT NULL DEFAULT 1,
health_multiplier REAL NOT NULL DEFAULT 1,
damage_multiplier REAL NOT NULL DEFAULT 1,
experience_multiplier REAL NOT NULL DEFAULT 1,
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS dungeon_difficulties (
dungeon_id INTEGER NOT NULL REFERENCES dungeons(id) ON DELETE CASCADE,
difficulty_id INTEGER NOT NULL REFERENCES difficulties(id),
PRIMARY KEY (dungeon_id, difficulty_id)
);
CREATE TABLE IF NOT EXISTS encounters (
id INTEGER PRIMARY KEY,
dungeon_id INTEGER NOT NULL REFERENCES dungeons(id),
sequence INTEGER NOT NULL,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
encounter_type TEXT NOT NULL CHECK (encounter_type IN ('trash', 'boss')),
max_health INTEGER NOT NULL,
base_damage INTEGER NOT NULL,
tank_damage INTEGER NOT NULL,
party_damage INTEGER NOT NULL,
description TEXT NOT NULL,
image_url TEXT NOT NULL DEFAULT '/boss-placeholder.svg',
UNIQUE (dungeon_id, sequence)
);
CREATE TABLE IF NOT EXISTS mechanics (
id INTEGER PRIMARY KEY,
encounter_id INTEGER NOT NULL REFERENCES encounters(id) ON DELETE CASCADE,
name TEXT NOT NULL,
mechanic_type TEXT NOT NULL,
interval_seconds REAL,
power INTEGER NOT NULL DEFAULT 0,
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS classes (
id INTEGER PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
resource_name TEXT NOT NULL,
max_resource INTEGER NOT NULL DEFAULT 100,
theme_color TEXT NOT NULL DEFAULT '#e5b95f',
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS spells (
id INTEGER PRIMARY KEY,
class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
spell_type TEXT NOT NULL,
resource_cost INTEGER NOT NULL,
cooldown_seconds REAL NOT NULL DEFAULT 0,
power INTEGER NOT NULL,
unlock_level INTEGER NOT NULL DEFAULT 1,
glyph TEXT NOT NULL DEFAULT '+',
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
slot TEXT NOT NULL CHECK (slot IN ('weapon', 'helmet', 'chest', 'gloves', 'boots', 'pants', 'ring', 'necklace', 'trinket', 'component')),
rarity TEXT NOT NULL,
item_level INTEGER NOT NULL,
healing_power INTEGER NOT NULL DEFAULT 0,
max_resource_bonus INTEGER NOT NULL DEFAULT 0,
glyph TEXT NOT NULL DEFAULT '?',
image_url TEXT NOT NULL DEFAULT '/equipment-placeholder.svg',
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS encounter_loot (
encounter_id INTEGER NOT NULL REFERENCES encounters(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
difficulty_id INTEGER REFERENCES difficulties(id),
drop_weight INTEGER NOT NULL DEFAULT 100,
drop_chance REAL NOT NULL DEFAULT 0.65 CHECK (drop_chance BETWEEN 0 AND 1),
PRIMARY KEY (encounter_id, difficulty_id, item_id)
);
CREATE TABLE IF NOT EXISTS dungeon_completion_loot (
dungeon_id INTEGER NOT NULL REFERENCES dungeons(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
PRIMARY KEY (dungeon_id, item_id)
);
CREATE TABLE IF NOT EXISTS crafting_recipes (
id INTEGER PRIMARY KEY,
item_id INTEGER NOT NULL UNIQUE REFERENCES items(id) ON DELETE CASCADE,
difficulty_id INTEGER REFERENCES difficulties(id),
source_dungeon_id INTEGER REFERENCES dungeons(id) ON DELETE CASCADE,
source_encounter_id INTEGER REFERENCES encounters(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS crafting_recipe_components (
recipe_id INTEGER NOT NULL REFERENCES crafting_recipes(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
quantity INTEGER NOT NULL CHECK (quantity > 0),
PRIMARY KEY (recipe_id, item_id)
);
CREATE TABLE IF NOT EXISTS item_sets (
id INTEGER PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS item_set_items (
set_id INTEGER NOT NULL REFERENCES item_sets(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL UNIQUE REFERENCES items(id) ON DELETE CASCADE,
PRIMARY KEY (set_id, item_id)
);
CREATE TABLE IF NOT EXISTS item_set_bonuses (
id INTEGER PRIMARY KEY,
set_id INTEGER NOT NULL REFERENCES item_sets(id) ON DELETE CASCADE,
required_pieces INTEGER NOT NULL CHECK (required_pieces > 0),
effect_type TEXT NOT NULL,
description TEXT NOT NULL,
UNIQUE (set_id, required_pieces)
);
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL UNIQUE COLLATE NOCASE,
password_hash TEXT NOT NULL,
password_salt TEXT NOT NULL,
completed_dungeon_parts INTEGER NOT NULL DEFAULT 0,
completed_raid_phases INTEGER NOT NULL DEFAULT 0,
created_ip TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS account_ip_allowances (
ip_address TEXT PRIMARY KEY,
max_accounts INTEGER NOT NULL CHECK (max_accounts >= 1),
note TEXT NOT NULL DEFAULT '',
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS characters (
id INTEGER PRIMARY KEY,
account_id INTEGER REFERENCES accounts(id) ON DELETE CASCADE,
class_id INTEGER NOT NULL REFERENCES classes(id),
name TEXT NOT NULL,
level INTEGER NOT NULL DEFAULT 1,
experience INTEGER NOT NULL DEFAULT 0,
talent_points INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (account_id, class_id)
);
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY,
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL UNIQUE,
active_character_id INTEGER REFERENCES characters(id),
expires_at TEXT NOT NULL,
created_ip TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS sessions_token_hash_idx ON sessions(token_hash);
CREATE INDEX IF NOT EXISTS sessions_expires_at_idx ON sessions(expires_at);
CREATE TABLE IF NOT EXISTS character_ability_slots (
character_id INTEGER NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
slot_number INTEGER NOT NULL CHECK (slot_number BETWEEN 1 AND 6),
spell_id INTEGER REFERENCES spells(id),
PRIMARY KEY (character_id, slot_number),
UNIQUE (character_id, spell_id)
);
CREATE TABLE IF NOT EXISTS talents (
id INTEGER PRIMARY KEY,
class_id INTEGER NOT NULL REFERENCES classes(id) ON DELETE CASCADE,
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
max_rank INTEGER NOT NULL DEFAULT 1,
tier INTEGER NOT NULL DEFAULT 1,
branch INTEGER NOT NULL DEFAULT 1,
prerequisite_talent_id INTEGER REFERENCES talents(id),
prerequisite_rank INTEGER NOT NULL DEFAULT 0,
effect_type TEXT NOT NULL DEFAULT 'placeholder',
effect_value_per_rank REAL NOT NULL DEFAULT 0,
glyph TEXT NOT NULL DEFAULT '+',
description TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS character_talents (
character_id INTEGER NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
talent_id INTEGER NOT NULL REFERENCES talents(id) ON DELETE CASCADE,
rank INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (character_id, talent_id)
);
CREATE TABLE IF NOT EXISTS level_progression (
level INTEGER PRIMARY KEY CHECK (level BETWEEN 1 AND 25),
experience_required INTEGER NOT NULL,
talent_points_total INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS game_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS character_inventory (
character_id INTEGER NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id),
quantity INTEGER NOT NULL DEFAULT 1,
equipped INTEGER NOT NULL DEFAULT 0 CHECK (equipped IN (0, 1)),
PRIMARY KEY (character_id, item_id)
);
CREATE TABLE IF NOT EXISTS encounter_loot_rolls (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
run_token TEXT NOT NULL,
encounter_id INTEGER NOT NULL REFERENCES encounters(id),
difficulty_id INTEGER NOT NULL REFERENCES difficulties(id),
item_id INTEGER REFERENCES items(id),
dropped INTEGER NOT NULL CHECK (dropped IN (0, 1)),
was_duplicate INTEGER NOT NULL DEFAULT 0 CHECK (was_duplicate IN (0, 1)),
quantity_after INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (character_id, run_token, encounter_id, difficulty_id)
);
CREATE TABLE IF NOT EXISTS encounter_loot_roll_items (
roll_id INTEGER NOT NULL REFERENCES encounter_loot_rolls(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id),
quantity INTEGER NOT NULL DEFAULT 1 CHECK (quantity > 0),
was_duplicate INTEGER NOT NULL DEFAULT 0 CHECK (was_duplicate IN (0, 1)),
quantity_after INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (roll_id, item_id)
);
CREATE TABLE IF NOT EXISTS dungeon_runs (
id INTEGER PRIMARY KEY,
character_id INTEGER NOT NULL REFERENCES characters(id),
dungeon_id INTEGER NOT NULL REFERENCES dungeons(id),
difficulty_id INTEGER REFERENCES difficulties(id),
result TEXT NOT NULL CHECK (result IN ('active', 'victory', 'defeat', 'abandoned')),
character_name TEXT NOT NULL DEFAULT '',
class_name TEXT NOT NULL DEFAULT '',
character_level INTEGER NOT NULL DEFAULT 1,
average_item_level REAL NOT NULL DEFAULT 1,
resource_spent INTEGER NOT NULL DEFAULT 0,
duration_seconds INTEGER NOT NULL DEFAULT 0,
leaderboard_eligible INTEGER NOT NULL DEFAULT 0 CHECK (leaderboard_eligible IN (0, 1)),
start_part INTEGER NOT NULL DEFAULT 1,
completed_parts INTEGER NOT NULL DEFAULT 1,
started_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_at TEXT
);