2024-04-20 20:35:07 -07:00
|
|
|
import json
|
2024-04-20 20:35:24 -07:00
|
|
|
|
2024-03-24 16:56:13 -07:00
|
|
|
from ttfrog.db import schema
|
|
|
|
|
|
|
|
|
2024-04-20 20:35:07 -07:00
|
|
|
def test_manage_character(db, classes_factory, ancestries_factory):
|
2024-03-24 16:56:13 -07:00
|
|
|
with db.transaction():
|
2024-04-14 11:37:34 -07:00
|
|
|
# load the fixtures so they are bound to the current session
|
|
|
|
classes = classes_factory()
|
|
|
|
ancestries = ancestries_factory()
|
2024-04-20 23:40:17 -07:00
|
|
|
darkvision = db.AncestryTrait.filter_by(name="Darkvision")[0]
|
2024-03-24 16:56:13 -07:00
|
|
|
|
|
|
|
# create a human character (the default)
|
2024-03-26 00:53:21 -07:00
|
|
|
char = schema.Character(name="Test Character")
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-24 16:56:13 -07:00
|
|
|
assert char.id == 1
|
|
|
|
assert char.armor_class == 10
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.name == "Test Character"
|
|
|
|
assert char.ancestry.name == "human"
|
2024-03-24 16:56:13 -07:00
|
|
|
assert darkvision not in char.traits
|
|
|
|
|
|
|
|
# switch ancestry to tiefling
|
2024-03-26 00:53:21 -07:00
|
|
|
char.ancestry = ancestries["tiefling"]
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-24 16:56:13 -07:00
|
|
|
char = db.session.get(schema.Character, 1)
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.ancestry.name == "tiefling"
|
2024-03-24 16:56:13 -07:00
|
|
|
assert darkvision in char.traits
|
|
|
|
|
2024-04-20 23:27:47 -07:00
|
|
|
# switch ancestry to dragonborn and assert darkvision persists
|
|
|
|
char.ancestry = ancestries["dragonborn"]
|
|
|
|
db.add_or_update(char)
|
|
|
|
assert darkvision in char.traits
|
|
|
|
|
|
|
|
# switch ancestry to human and assert darkvision is removed
|
|
|
|
char.ancestry = ancestries["human"]
|
|
|
|
db.add_or_update(char)
|
|
|
|
assert darkvision not in char.traits
|
|
|
|
|
2024-03-24 16:56:13 -07:00
|
|
|
# assign a class and level
|
2024-03-26 00:53:21 -07:00
|
|
|
char.add_class(classes["fighter"], level=1)
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.levels == {"fighter": 1}
|
2024-03-24 16:56:13 -07:00
|
|
|
assert char.level == 1
|
2024-03-26 21:58:04 -07:00
|
|
|
assert char.class_attributes == {}
|
|
|
|
|
|
|
|
# 'fighting style' is available, but not at this level
|
2024-04-20 23:27:47 -07:00
|
|
|
fighter = classes["fighter"]
|
|
|
|
fighting_style = fighter.attributes_by_level[2]["Fighting Style"]
|
2024-03-26 21:58:04 -07:00
|
|
|
assert char.add_class_attribute(fighting_style, fighting_style.options[0]) is False
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-26 21:58:04 -07:00
|
|
|
assert char.class_attributes == {}
|
2024-03-24 16:56:13 -07:00
|
|
|
|
|
|
|
# level up
|
2024-03-26 00:53:21 -07:00
|
|
|
char.add_class(classes["fighter"], level=2)
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.levels == {"fighter": 2}
|
2024-03-24 16:56:13 -07:00
|
|
|
assert char.level == 2
|
|
|
|
|
2024-04-20 20:35:07 -07:00
|
|
|
# Assert the fighting style is added automatically and idempotent...ly?
|
2024-03-26 21:58:04 -07:00
|
|
|
assert char.class_attributes[fighting_style.name] == fighting_style.options[0]
|
2024-04-20 20:35:07 -07:00
|
|
|
assert char.add_class_attribute(fighting_style, fighting_style.options[0]) is True
|
|
|
|
db.add_or_update(char)
|
2024-03-26 21:58:04 -07:00
|
|
|
|
|
|
|
# classes
|
2024-03-26 00:53:21 -07:00
|
|
|
char.add_class(classes["rogue"], level=1)
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-24 16:56:13 -07:00
|
|
|
assert char.level == 3
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.levels == {"fighter": 2, "rogue": 1}
|
2024-03-24 16:56:13 -07:00
|
|
|
|
|
|
|
# remove a class
|
2024-03-26 00:53:21 -07:00
|
|
|
char.remove_class(classes["rogue"])
|
2024-04-20 20:35:07 -07:00
|
|
|
db.add_or_update(char)
|
2024-03-26 00:53:21 -07:00
|
|
|
assert char.levels == {"fighter": 2}
|
2024-03-24 16:56:13 -07:00
|
|
|
assert char.level == 2
|
|
|
|
|
2024-04-20 20:35:07 -07:00
|
|
|
# remove remaining class by setting level to zero
|
|
|
|
char.add_class(classes["fighter"], level=0)
|
|
|
|
db.add_or_update(char)
|
|
|
|
assert char.levels == {}
|
2024-03-24 16:56:13 -07:00
|
|
|
|
2024-03-26 21:58:04 -07:00
|
|
|
# ensure we're not persisting any orphan records in the map tables
|
2024-04-20 20:35:07 -07:00
|
|
|
dump = json.loads(db.dump())
|
|
|
|
assert dump["class_map"] == []
|
2024-03-26 21:58:04 -07:00
|
|
|
assert dump["character_class_attribute_map"] == []
|
2024-04-20 23:27:47 -07:00
|
|
|
|
|
|
|
|
|
|
|
def test_ancestries(db):
|
|
|
|
with db.transaction():
|
|
|
|
# create the Pygmy Orc ancestry
|
|
|
|
porc = schema.Ancestry(
|
|
|
|
name="Pygmy Orc",
|
|
|
|
size="Small",
|
|
|
|
speed=25,
|
|
|
|
)
|
|
|
|
db.add_or_update(porc)
|
|
|
|
assert porc.name == "Pygmy Orc"
|
|
|
|
assert porc.creature_type == "humanoid"
|
|
|
|
assert porc.size == "Small"
|
|
|
|
assert porc.speed == 25
|
|
|
|
|
|
|
|
# create the Relentless Endurance trait and add it to the Orc
|
|
|
|
endurance = schema.AncestryTrait(name="Relentless Endurance")
|
|
|
|
db.add_or_update(endurance)
|
|
|
|
porc.add_trait(endurance, level=1)
|
|
|
|
db.add_or_update(porc)
|
|
|
|
assert endurance in porc.traits
|
|
|
|
|
|
|
|
# now create an orc character and assert it gets Relentless Endurance
|
|
|
|
grognak = schema.Character(name="Grognak the Mighty", ancestry=porc)
|
|
|
|
assert endurance in grognak.traits
|