167 lines
6.0 KiB
Python
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
|