tabletop-frog/ttfrog/db/bootstrap.py
2024-02-26 01:12:45 -08:00

167 lines
6.0 KiB
Python

import logging
from ttfrog.db.manager import db
from ttfrog.db import schema
from sqlalchemy.exc import IntegrityError
# move this to json or whatever
data = {
'CharacterClass': [
{
'id': 1,
'name': 'fighter',
'hit_dice': '1d10',
'hit_dice_stat': 'CON',
'proficiencies': 'all armor, all shields, simple weapons, martial weapons',
'saving_throws': ['STR, CON'],
'skills': ['Acrobatics', 'Animal Handling', 'Athletics', 'History', 'Insight', 'Intimidation', 'Perception', 'Survival'],
},
{
'id': 2,
'name': 'rogue',
'hit_dice': '1d8',
'hit_dice_stat': 'DEX',
'proficiencies': 'simple weapons, hand crossbows, longswords, rapiers, shortswords',
'saving_throws': ['DEX', 'INT'],
'skills': ['Acrobatics', 'Athletics', 'Deception', 'Insight', 'Intimidation', 'Investigation', 'Perception', 'Performance', 'Persuasion', 'Sleight of Hand', 'Stealth'],
},
],
'Skill': [
{'name': 'Acrobatics'},
{'name': 'Animal Handling'},
{'name': 'Athletics'},
{'name': 'Deception'},
{'name': 'History'},
{'name': 'Insight'},
{'name': 'Intimidation'},
{'name': 'Investigation'},
{'name': 'Perception'},
{'name': 'Performance'},
{'name': 'Persuasion'},
{'name': 'Sleight of Hand'},
{'name': 'Stealth'},
{'name': 'Survival'},
],
'Ancestry': [
{'id': 1, 'name': 'human', 'creature_type': 'humanoid'},
{'id': 2, 'name': 'dragonborn', 'creature_type': 'humanoid'},
{'id': 3, 'name': 'tiefling', 'creature_type': 'humanoid'},
{'id': 4, 'name': 'elf', 'creature_type': 'humanoid'},
],
'AncestryTrait': [
{'id': 1, 'name': '+1 to All Ability Scores', },
{'id': 2, 'name': 'Breath Weapon', },
{'id': 3, 'name': 'Darkvision', },
],
'AncestryTraitMap': [
{'ancestry_id': 1, 'ancestry_trait_id': 1, 'level': 1}, # human +1 to scores
{'ancestry_id': 2, 'ancestry_trait_id': 2, 'level': 1}, # dragonborn breath weapon
{'ancestry_id': 3, 'ancestry_trait_id': 3, 'level': 1}, # tiefling darkvision
{'ancestry_id': 2, 'ancestry_trait_id': 2, 'level': 1}, # elf darkvision
],
'CharacterClassMap': [
{
'character_id': 1,
'character_class_id': 1,
'level': 2,
},
{
'character_id': 1,
'character_class_id': 2,
'level': 3,
},
],
'Character': [
{
'id': 1,
'name': 'Sabetha',
'ancestry_id': 1,
'armor_class': 10,
'max_hit_points': 14,
'hit_points': 14,
'temp_hit_points': 0,
'speed': 30,
'str': 16,
'dex': 12,
'con': 18,
'int': 11,
'wis': 12,
'cha': 8,
'proficiencies': 'all armor, all shields, simple weapons, martial weapons',
'saving_throws': ['STR', 'CON'],
'skills': ['Acrobatics', 'Animal Handling'],
},
],
'ClassAttribute': [
{'id': 1, 'name': 'Fighting Style'},
{'id': 2, 'name': 'Another Attribute'},
],
'ClassAttributeOption': [
{'id': 1, 'attribute_id': 1, 'name': 'Archery'},
{'id': 2, 'attribute_id': 1, 'name': 'Battlemaster'},
{'id': 3, 'attribute_id': 2, 'name': 'Another Option 1'},
{'id': 4, 'attribute_id': 2, 'name': 'Another Option 2'},
],
'ClassAttributeMap': [
{'class_attribute_id': 1, 'character_class_id': 1, 'level': 2}, # Fighter: Fighting Style
{'class_attribute_id': 2, 'character_class_id': 1, 'level': 1}, # Fighter: Another Attr
],
'CharacterClassAttributeMap': [
{'character_id': 1, 'class_attribute_id': 2, 'option_id': 4}, # Sabetha, another option, option 2
{'character_id': 1, 'class_attribute_id': 1, 'option_id': 1}, # Sabetha, fighting style, archery
],
'Modifier': [
# Humans
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'str'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'dex'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'con'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'int'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'wis'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 1, 'value': '+1', 'type': 'stat', 'target': 'cha'},
# Dragonborn
{'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '60', 'type': 'attribute ', 'target': 'Darkvision'},
{'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '+1', 'type': 'stat', 'target': ''},
{'source_table_name': 'ancestry_trait', 'source_table_id': 2, 'value': '+1', 'type': 'stat', 'target': ''},
# Fighting Style: Archery
{'source_table_name': 'class_attribute', 'source_table_id': 1, 'value': '+2', 'type': 'weapon ', 'target': 'ranged'},
],
}
def bootstrap():
"""
Initialize the database with source data. Idempotent; will skip anything that already exists.
"""
db.init()
for table, records in data.items():
model = getattr(schema, table)
for rec in records:
obj = model(**rec)
try:
with db.transaction():
db.session.add(obj)
logging.info(f"Created {table} {obj}")
except IntegrityError as e:
if 'UNIQUE constraint failed' in str(e):
logging.info(f"Skipping existing {table} {obj}")
continue
raise