tabletop-frog/test/test_inventories.py

280 lines
9.8 KiB
Python

from ttfrog.db.schema import prototypes
from ttfrog.db.schema.inventory import InventoryType
def test_spell_inventory(db, carl):
with db.transaction():
fireball = prototypes.BaseSpell(name="Fireball", level=3, concentration=False)
db.add_or_update([fireball, carl])
assert fireball not in carl.spells
assert carl.spells.learn(fireball)
db.add_or_update(carl)
assert fireball in carl.spells
assert fireball in carl.spells.known
assert fireball in carl.spells.available
assert fireball not in carl.spells.prepared
prestidigitation = prototypes.BaseSpell(name="Prestidigitation", level=0, concentration=False)
wish = prototypes.BaseSpell(name="Wish", level=9, concentration=False)
spellbook = prototypes.BaseItem(name="Spell Book", inventory_type=InventoryType.SPELL)
db.add_or_update([wish, spellbook])
assert wish not in carl.spells
grimoire = carl.equipment.add(spellbook)
db.add_or_update(carl)
grimoire.inventory.add(wish)
grimoire.inventory.add(prestidigitation)
db.add_or_update(carl)
assert wish in carl.spells.available
assert wish not in carl.spells.known
assert prestidigitation in carl.spells.available
assert prestidigitation not in carl.spells.known
assert carl.spells.get(wish)
assert carl.spells.get(prestidigitation)
def test_equipment_inventory(db, carl):
with db.transaction():
# trigger the creation of inventory mappings
db.add_or_update(carl)
# create some items
ten_foot_pole = prototypes.BaseItem(name="10ft. Pole", item_type=prototypes.ItemType.ITEM, consumable=False)
db.add_or_update(ten_foot_pole)
# add the pole to carl's equipment, and the spell to his spell list.
assert carl.equipment.add(ten_foot_pole)
# can't mix and match inventory item types
assert not carl.spells.learn(ten_foot_pole)
# add two more 10 foot poles. You can never have too many.
assert carl.equipment.add(ten_foot_pole)
assert carl.equipment.add(ten_foot_pole)
db.add_or_update(carl)
all_carls_poles = carl.equipment.get_all(ten_foot_pole)
assert len(all_carls_poles) == 3
# check the "contains" logic
assert ten_foot_pole in carl.equipment
assert ten_foot_pole not in carl.spells
pole_one = all_carls_poles[0]
# equip one pole
assert pole_one.equip()
# can't equip it twice
assert not pole_one.equip()
# not consumable or attunable
assert not pole_one.consume()
assert not pole_one.attune()
assert pole_one.unequip()
# can't unequip the unequipped ones
assert not all_carls_poles[1].unequip()
assert not all_carls_poles[2].unequip()
# drop one pole
assert carl.equipment.remove(pole_one)
assert ten_foot_pole in carl.equipment
return
# drop the remaining poles
assert carl.equipment.remove(all_carls_poles[1])
assert carl.equipment.remove(all_carls_poles[2])
assert ten_foot_pole not in carl.equipment
# can't drop what you don't have
assert not carl.equipment.remove(pole_one)
def test_inventory_bundles(db, carl):
with db.transaction():
arrows = prototypes.BaseItem(name="Arrows", item_type=prototypes.ItemType.ITEM, consumable=True, count=20)
db.add_or_update([carl, arrows])
quiver = carl.equipment.add(arrows)
db.add_or_update([carl, quiver])
assert quiver.container == carl.equipment
# full quiver
assert arrows in carl.equipment
assert quiver.count == 20
# use one
assert quiver.consume(1) == 19
assert quiver.count == 19
# cannot use more than you have
assert not quiver.consume(20)
# cannot use a negative amount
assert not quiver.consume(-1)
# consume all remaining arrows
assert quiver.consume(19) == 0
assert arrows not in carl.equipment
def test_spell_slots(db, carl, wizard):
with db.transaction():
prestidigitation = prototypes.BaseSpell(name="Prestidigitation", level=0, concentration=False)
fireball = prototypes.BaseSpell(name="Fireball", level=3, concentration=False)
db.add_or_update([carl, prestidigitation, fireball])
carl.spells.learn(prestidigitation)
carl.spells.learn(fireball)
db.add_or_update(carl)
# verify carl has the spell slots granted by wizard at 1st level
assert len(carl.spell_slots) == 2
assert carl.spell_slots[0].spell_level == 1
assert carl.spell_slots[1].spell_level == 1
# carl knows the spells but hasn't prepared them
assert prestidigitation in carl.spells
assert fireball in carl.spells
assert prestidigitation not in carl.spells.prepared
assert fireball not in carl.spells.prepared
# prepare the cantrip
assert carl.spells.prepare(prestidigitation)
assert carl.spells.cast(prestidigitation)
# can't prepare a 3rd level spell if you don't have 3rd level slots
assert carl.spellcaster_level == 1
assert not carl.spells.prepare(fireball)
# make carl a 5th level wizard so he gets a 3rd level spell slot
carl.level_up(wizard, num_levels=4)
assert carl.level == 5
assert carl.spellcaster_level == 3
# cast fireball until he's out of 3rd level slots
assert not carl.spells.cast(fireball)
assert carl.spells.prepare(fireball)
assert carl.spells.cast(fireball)
assert carl.spells.cast(fireball)
assert not carl.spells.cast(fireball)
# level up to 7th level, gaining 1 4th level slot and 1 more 3rd level slot
carl.add_class(wizard)
carl.level_up(wizard, num_levels=2)
assert carl.spellcaster_level == 4
assert len(carl.spell_slots_available[4]) == 1
assert len(carl.spell_slots_available[3]) == 1
# cast at 4th level
assert carl.spells.cast(fireball, level=4)
assert not carl.spells.cast(fireball, level=4)
# use the last 3rd level slot
assert carl.spells.cast(fireball)
assert not carl.spells.cast(fireball)
# unprepare it
assert carl.spells.unprepare(fireball)
assert not carl.spells.unprepare(fireball)
def test_containers(db, carl):
with db.transaction():
ten_foot_pole = prototypes.BaseItem(name="10ft. Pole")
coil_of_rope = prototypes.BaseItem(name="50 ft. of Rope", consumable=True, count=50)
bag_of_holding = prototypes.BaseItem(name="Bag of Holding", inventory_type=InventoryType.EQUIPMENT)
db.add_or_update([ten_foot_pole, coil_of_rope, bag_of_holding])
pole = carl.equipment.add(ten_foot_pole)
rope = carl.equipment.add(coil_of_rope)
bag = carl.equipment.add(bag_of_holding)
db.add_or_update(carl)
# verify the bag of holding's inventory is created automatically.
assert bag.inventory_type is not None
assert bag.inventory is not None
# the existing instances are found using the get() method
assert carl.equipment.get(bag_of_holding) == bag
assert carl.equipment.get(ten_foot_pole) == pole
assert carl.equipment.get(coil_of_rope) == rope
# backreferences are populated correctly
assert pole.container == carl.equipment
# add some items to the bag of holding
assert pole.move_to(bag)
assert rope.move_to(bag)
assert pole.container.id == bag.inventory.id
assert pole.container == bag.inventory
assert pole in bag.inventory
assert pole in bag
assert pole not in carl.equipment.contents
assert pole.container == bag.inventory
pole_from_bag = bag.inventory.get(ten_foot_pole)
rope_from_bag = bag.inventory.get(coil_of_rope)
assert pole_from_bag.prototype == ten_foot_pole
assert pole_from_bag in bag
bag_inventory_size = 2 # one pole, one rope
equipment_size = 1 # one bag
# one bag, one pole, one rope
total_inventory_size = bag_inventory_size + equipment_size
assert len(list(bag.inventory.contents)) == bag_inventory_size
assert len(list(carl.equipment.contents)) == equipment_size
assert len(list(carl.equipment.all_contents)) == total_inventory_size
# nested containers!
assert pole_from_bag in carl.equipment
assert rope_from_bag in carl.equipment
# test equality of mappings
carls_bag = carl.equipment.get(bag_of_holding)
carls_pole = carl.equipment.get(ten_foot_pole)
carls_rope = carl.equipment.get(coil_of_rope)
assert carls_pole == pole_from_bag
assert carls_rope == rope_from_bag
# use some rope
assert carls_rope.consume(10)
assert carls_rope.count == 40
# move the rope out of the bag of holding, but not the pole
assert carls_rope in carls_bag
assert carls_rope.move_to(carl.equipment)
assert carls_rope not in carls_bag
assert carls_pole in carls_bag
# get the db record anew, in case the in-memory representation isn't
# what's recorded in the database. Then make sure we didn't break
# anything by asserting we still only have 40ft of rope.
carl = db.Character.filter_by(name="carl").one()
assert carls_rope in carl.equipment
assert carls_rope not in carl.equipment.get(bag_of_holding)
assert carls_rope.count == 40
# old references are still valid
assert rope_from_bag == carls_rope
# use the rest of the rope
assert carls_rope.consume(40) == 0
assert rope_from_bag not in carl.equipment
assert rope_from_bag not in carl.equipment.get(bag_of_holding)