move inventory verbs to inventory map from character
This commit is contained in:
parent
0eda35b90d
commit
68a8f4920b
|
@ -10,7 +10,6 @@ from ttfrog.db.base import BaseObject, SlugMixin
|
||||||
from ttfrog.db.schema.classes import CharacterClass, ClassFeature
|
from ttfrog.db.schema.classes import CharacterClass, ClassFeature
|
||||||
from ttfrog.db.schema.constants import DamageType, Defenses
|
from ttfrog.db.schema.constants import DamageType, Defenses
|
||||||
from ttfrog.db.schema.inventory import Inventory, InventoryMap, InventoryType
|
from ttfrog.db.schema.inventory import Inventory, InventoryMap, InventoryType
|
||||||
from ttfrog.db.schema.item import ItemType
|
|
||||||
from ttfrog.db.schema.modifiers import Modifier, ModifierMixin, Stat
|
from ttfrog.db.schema.modifiers import Modifier, ModifierMixin, Stat
|
||||||
from ttfrog.db.schema.skill import Skill
|
from ttfrog.db.schema.skill import Skill
|
||||||
|
|
||||||
|
@ -422,47 +421,6 @@ class Character(BaseObject, SlugMixin, ModifierMixin):
|
||||||
mapping.attuned = False
|
mapping.attuned = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def equip(self, mapping):
|
|
||||||
if mapping.equipped:
|
|
||||||
return False
|
|
||||||
mapping.equipped = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
def unequip(self, mapping):
|
|
||||||
if not mapping.equipped:
|
|
||||||
return False
|
|
||||||
mapping.equipped = False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def prepare(self, mapping):
|
|
||||||
if mapping.item.item_type != ItemType.SPELL:
|
|
||||||
return False
|
|
||||||
if mapping.item.level > 0 and not self.spell_slots_by_level[mapping.item.level]:
|
|
||||||
return False
|
|
||||||
return self.equip(mapping)
|
|
||||||
|
|
||||||
def unprepare(self, mapping):
|
|
||||||
if mapping.item.item_type != ItemType.SPELL:
|
|
||||||
return False
|
|
||||||
return self.unequip(mapping)
|
|
||||||
|
|
||||||
def cast(self, mapping: InventoryMap, level=0):
|
|
||||||
if not mapping.prepared:
|
|
||||||
return False
|
|
||||||
if not level:
|
|
||||||
level = mapping.item.level
|
|
||||||
|
|
||||||
# cantrips
|
|
||||||
if level == 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# expend the spell slot
|
|
||||||
avail = self.spell_slots_available[level]
|
|
||||||
if not avail:
|
|
||||||
return False
|
|
||||||
avail[0].expended = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
def level_in_class(self, charclass):
|
def level_in_class(self, charclass):
|
||||||
mapping = [mapping for mapping in self.class_map if mapping.character_class_id == charclass.id]
|
mapping = [mapping for mapping in self.class_map if mapping.character_class_id == charclass.id]
|
||||||
if not mapping:
|
if not mapping:
|
||||||
|
|
|
@ -41,6 +41,8 @@ class Inventory(BaseObject):
|
||||||
uselist=True, cascade="all,delete,delete-orphan", lazy="immediate", default_factory=lambda: []
|
uselist=True, cascade="all,delete,delete-orphan", lazy="immediate", default_factory=lambda: []
|
||||||
)
|
)
|
||||||
|
|
||||||
|
character = relationship("Character", init=False, viewonly=True, lazy="immediate")
|
||||||
|
|
||||||
def get(self, item):
|
def get(self, item):
|
||||||
return self.get_all(item)[0]
|
return self.get_all(item)[0]
|
||||||
|
|
||||||
|
@ -101,6 +103,30 @@ class InventoryMap(BaseObject):
|
||||||
if self.item.item_type == ItemType.SPELL:
|
if self.item.item_type == ItemType.SPELL:
|
||||||
return self.equipped or self.always_prepared
|
return self.equipped or self.always_prepared
|
||||||
|
|
||||||
|
def equip(self):
|
||||||
|
if self.equipped:
|
||||||
|
return False
|
||||||
|
self.equipped = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unequip(self):
|
||||||
|
if not self.equipped:
|
||||||
|
return False
|
||||||
|
self.equipped = False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
if self.item.item_type != ItemType.SPELL:
|
||||||
|
return False
|
||||||
|
if self.item.level > 0 and not self.inventory.character.spell_slots_by_level[self.item.level]:
|
||||||
|
return False
|
||||||
|
return self.equip()
|
||||||
|
|
||||||
|
def unprepare(self):
|
||||||
|
if self.item.item_type != ItemType.SPELL:
|
||||||
|
return False
|
||||||
|
return self.unequip()
|
||||||
|
|
||||||
def use(self, item_property: ItemProperty, charges=None):
|
def use(self, item_property: ItemProperty, charges=None):
|
||||||
if item_property.charge_cost is None:
|
if item_property.charge_cost is None:
|
||||||
return True
|
return True
|
||||||
|
@ -126,6 +152,42 @@ class InventoryMap(BaseObject):
|
||||||
return 0
|
return 0
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
|
def cast(self, level=0):
|
||||||
|
if self.item.item_type != ItemType.SPELL:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not self.prepared:
|
||||||
|
return False
|
||||||
|
if not level:
|
||||||
|
level = self.item.level
|
||||||
|
|
||||||
|
# cantrips
|
||||||
|
if level == 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# expend the spell slot
|
||||||
|
avail = self.inventory.character.spell_slots_available[level]
|
||||||
|
if not avail:
|
||||||
|
return False
|
||||||
|
avail[0].expended = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def attune(self):
|
||||||
|
if self.attuned:
|
||||||
|
return False
|
||||||
|
if not self.item.requires_attunement:
|
||||||
|
return False
|
||||||
|
if len(self.inventory.character.attuned_items) >= 3:
|
||||||
|
return False
|
||||||
|
self.attuned = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unattune(self):
|
||||||
|
if not self.attuned:
|
||||||
|
return False
|
||||||
|
self.attuned = False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Charge(BaseObject):
|
class Charge(BaseObject):
|
||||||
__tablename__ = "charge"
|
__tablename__ = "charge"
|
||||||
|
|
|
@ -33,21 +33,23 @@ def test_equipment_inventory(db, carl):
|
||||||
assert fireball in carl.spells
|
assert fireball in carl.spells
|
||||||
assert fireball not in carl.equipment
|
assert fireball not in carl.equipment
|
||||||
|
|
||||||
|
pole_one = all_carls_poles[0]
|
||||||
|
|
||||||
# equip one pole
|
# equip one pole
|
||||||
assert carl.equip(all_carls_poles[0])
|
assert pole_one.equip()
|
||||||
|
|
||||||
# can't equip it twice
|
# can't equip it twice
|
||||||
assert not carl.equip(all_carls_poles[0])
|
assert not pole_one.equip()
|
||||||
|
|
||||||
# unequip it
|
# unequip it
|
||||||
assert carl.unequip(all_carls_poles[0])
|
assert pole_one.unequip()
|
||||||
|
|
||||||
# can't unequip the unequipped ones
|
# can't unequip the unequipped ones
|
||||||
assert not carl.unequip(all_carls_poles[1])
|
assert not all_carls_poles[1].unequip()
|
||||||
assert not carl.unequip(all_carls_poles[2])
|
assert not all_carls_poles[2].unequip()
|
||||||
|
|
||||||
# drop one pole
|
# drop one pole
|
||||||
assert carl.equipment.remove(all_carls_poles[0])
|
assert carl.equipment.remove(pole_one)
|
||||||
assert ten_foot_pole in carl.equipment
|
assert ten_foot_pole in carl.equipment
|
||||||
|
|
||||||
# drop the remaining poles
|
# drop the remaining poles
|
||||||
|
@ -56,7 +58,7 @@ def test_equipment_inventory(db, carl):
|
||||||
assert ten_foot_pole not in carl.equipment
|
assert ten_foot_pole not in carl.equipment
|
||||||
|
|
||||||
# can't drop what you don't have
|
# can't drop what you don't have
|
||||||
assert not carl.equipment.remove(all_carls_poles[0])
|
assert not carl.equipment.remove(pole_one)
|
||||||
|
|
||||||
|
|
||||||
def test_inventory_bundles(db, carl):
|
def test_inventory_bundles(db, carl):
|
||||||
|
@ -108,15 +110,12 @@ def test_spell_slots(db, carl, wizard):
|
||||||
|
|
||||||
# prepare the cantrip
|
# prepare the cantrip
|
||||||
carls_prestidigitation = carl.spells.get(prestidigitation)
|
carls_prestidigitation = carl.spells.get(prestidigitation)
|
||||||
assert carl.prepare(carls_prestidigitation)
|
assert carls_prestidigitation.prepare()
|
||||||
assert carl.cast(carls_prestidigitation)
|
assert carls_prestidigitation.cast()
|
||||||
|
|
||||||
# prepare() and cast() require a spell from the spell inventory
|
|
||||||
carls_fireball = carl.spells.get(fireball)
|
|
||||||
|
|
||||||
# can't prepare a 3rd level spell if you don't have 3rd level slots
|
# can't prepare a 3rd level spell if you don't have 3rd level slots
|
||||||
assert carl.spellcaster_level == 1
|
assert carl.spellcaster_level == 1
|
||||||
assert not carl.prepare(carls_fireball)
|
assert not carl.spells.get(fireball).prepare()
|
||||||
|
|
||||||
# make carl a 5th level wizard so he gets a 3rd level spell slot
|
# make carl a 5th level wizard so he gets a 3rd level spell slot
|
||||||
carl.level_up(wizard, num_levels=4)
|
carl.level_up(wizard, num_levels=4)
|
||||||
|
@ -124,10 +123,10 @@ def test_spell_slots(db, carl, wizard):
|
||||||
assert carl.spellcaster_level == 3
|
assert carl.spellcaster_level == 3
|
||||||
|
|
||||||
# cast fireball until he's out of 3rd level slots
|
# cast fireball until he's out of 3rd level slots
|
||||||
assert carl.prepare(carls_fireball)
|
assert carl.spells.get(fireball).prepare()
|
||||||
assert carl.cast(carls_fireball)
|
assert carl.spells.get(fireball).cast()
|
||||||
assert carl.cast(carls_fireball)
|
assert carl.spells.get(fireball).cast()
|
||||||
assert not carl.cast(carls_fireball)
|
assert not carl.spells.get(fireball).cast()
|
||||||
|
|
||||||
# level up to 7th level, gaining 1 4th level slot and 1 more 3rd level slot
|
# level up to 7th level, gaining 1 4th level slot and 1 more 3rd level slot
|
||||||
carl.add_class(wizard)
|
carl.add_class(wizard)
|
||||||
|
@ -137,9 +136,9 @@ def test_spell_slots(db, carl, wizard):
|
||||||
assert len(carl.spell_slots_available[3]) == 1
|
assert len(carl.spell_slots_available[3]) == 1
|
||||||
|
|
||||||
# cast at 4th level
|
# cast at 4th level
|
||||||
assert carl.cast(carls_fireball, 4)
|
assert carl.spells.get(fireball).cast(level=4)
|
||||||
assert not carl.cast(carls_fireball, 4)
|
assert not carl.spells.get(fireball).cast(level=4)
|
||||||
|
|
||||||
# use the last 3rd level slot
|
# use the last 3rd level slot
|
||||||
assert carl.cast(carls_fireball)
|
assert carl.spells.get(fireball).cast()
|
||||||
assert not carl.cast(carls_fireball)
|
assert not carl.spells.get(fireball).cast()
|
||||||
|
|
|
@ -82,8 +82,8 @@ def test_charges(db, carl):
|
||||||
db.add_or_update(carl)
|
db.add_or_update(carl)
|
||||||
|
|
||||||
carls_dagger = carl.equipment.get(dagger_of_lulz)
|
carls_dagger = carl.equipment.get(dagger_of_lulz)
|
||||||
assert carl.equip(carls_dagger)
|
assert carls_dagger.equip()
|
||||||
assert carl.attune(carls_dagger)
|
assert carls_dagger.attune()
|
||||||
|
|
||||||
assert len(carls_dagger.charges) == dagger_of_lulz.charges == 6
|
assert len(carls_dagger.charges) == dagger_of_lulz.charges == 6
|
||||||
assert len(carls_dagger.charges_available) == dagger_of_lulz.charges == 6
|
assert len(carls_dagger.charges_available) == dagger_of_lulz.charges == 6
|
||||||
|
@ -132,24 +132,24 @@ def test_attunement(db, carl):
|
||||||
assert carl.armor_class == 10
|
assert carl.armor_class == 10
|
||||||
assert len(carl.attuned_items) == 0
|
assert len(carl.attuned_items) == 0
|
||||||
|
|
||||||
carl.equip(carls_shield)
|
carls_shield.equip()
|
||||||
|
|
||||||
assert plus_two_ac in carl.modifiers["armor_class"]
|
assert plus_two_ac in carl.modifiers["armor_class"]
|
||||||
assert ranged_resistance not in carl.modifiers[DamageType.ranged_weapon_attacks]
|
assert ranged_resistance not in carl.modifiers[DamageType.ranged_weapon_attacks]
|
||||||
assert carl.armor_class == 12
|
assert carl.armor_class == 12
|
||||||
assert carls_shield not in carl.attuned_items
|
assert carls_shield not in carl.attuned_items
|
||||||
|
|
||||||
carl.attune(carls_shield)
|
carls_shield.attune()
|
||||||
assert carl.armor_class == 12
|
assert carl.armor_class == 12
|
||||||
assert plus_two_ac in carl.modifiers["armor_class"]
|
assert plus_two_ac in carl.modifiers["armor_class"]
|
||||||
assert ranged_resistance in carl.modifiers[DamageType.ranged_weapon_attacks]
|
assert ranged_resistance in carl.modifiers[DamageType.ranged_weapon_attacks]
|
||||||
assert carls_shield in carl.attuned_items
|
assert carls_shield in carl.attuned_items
|
||||||
|
|
||||||
assert carl.equip(carl.equipment.get(helm))
|
assert carl.equipment.get(helm).equip()
|
||||||
assert carl.armor_class == 13
|
assert carl.armor_class == 13
|
||||||
|
|
||||||
assert carl.unattune(carls_shield)
|
assert carls_shield.unattune()
|
||||||
assert carl.armor_class == 13
|
assert carl.armor_class == 13
|
||||||
assert ranged_resistance not in carl.modifiers[DamageType.ranged_weapon_attacks]
|
assert ranged_resistance not in carl.modifiers[DamageType.ranged_weapon_attacks]
|
||||||
assert carl.unequip(carls_shield)
|
assert carls_shield.unequip()
|
||||||
assert carl.armor_class == 11
|
assert carl.armor_class == 11
|
||||||
|
|
Loading…
Reference in New Issue
Block a user