class LevelUp(models.Model):
    character = models.ForeignKey(Character, on_delete=models.CASCADE)
    hd_roll = models.IntegerField(verbose_name='HD Roll',
                                  validators=[validators.MinValueValidator(1)])
    md_roll = models.IntegerField(verbose_name='MD Roll',
                                  validators=[validators.MinValueValidator(1)])
    sd_roll = models.IntegerField(verbose_name='SD Roll',
                                  validators=[validators.MinValueValidator(1)])
    ad_roll = enumfields.EnumIntegerField(verbose_name='AD Roll',
                                          enum=Attribute, default=Attribute.stren)
    selected_attribute = enumfields.EnumIntegerField(verbose_name='Selected Attribute',
                                                     enum=Attribute, default=Attribute.stren)
class UnlockedAbility(models.Model):
    character = models.ForeignKey(Character, on_delete=models.CASCADE)
    ability_enum = enumfields.EnumIntegerField(abilities.Abilities)

    @property
    def ability(self) -> ability.Ability:
        return abilities.abilities[self.ability_enum]

    def __str__(self) -> str:
        return f'{self.character} {self.ability.name}'
예제 #3
0
class Locality(base.AbstractModel,
               metaclass=temporal.TemporalModelBase):

    class Meta(object):
        verbose_name = _('Locality')
        verbose_name_plural = _('Localities')

        ordering = ('abbrev',)
        default_permissions = ()

    sumiffiik = base.SumiffiikIDField()
    sumiffiik_domain = base.SumiffiikDomainField(
        default='https://data.gl/najugaq/locality',
    )

    code = models.PositiveSmallIntegerField(_('Code'),
                                            db_index=True, null=True)

    abbrev = models.CharField(_('Abbreviation'), max_length=4, null=True,
                              db_index=True)
    name = models.CharField(_('Name'), max_length=60,
                            db_index=True)

    type = enumfields.EnumIntegerField(LocalityType, verbose_name=_('Type'),
                                       db_index=True,
                                       default=LocalityType.UNKNOWN)
    locality_state = enumfields.EnumIntegerField(
        LocalityState, verbose_name=_('Locality State'),
        default=LocalityState.PROJECTED, db_index=True,
    )
    municipality = base.ForeignKey(Municipality, _('Municipality'),
                                   null=True, blank=True)
    district = base.ForeignKey(District, _('District'),
                               null=True, blank=True)
    postal_code = base.ForeignKey(PostalCode, _('Postal Code'),
                                  null=True, blank=True)

    def __str__(self):
        return self.name
class ItemQuantity(models.Model):
    class Meta:
        abstract = True

    slot = enumfields.EnumIntegerField(verbose_name='Slot',
                                       enum=equipment.Slot)
    quantity = models.IntegerField(
        default=1, validators=[validators.MinValueValidator(1)])
    item_index = models.IntegerField()

    @property
    def item(self) -> equipment.Item:
        return items.get_item(self.slot, self.item_index)
예제 #5
0
class Validator(ExceptionInfoMixin, models.Model):
    """ methods that are data validators """
    app_label = models.CharField(max_length=100)
    model_name = models.CharField(max_length=100)
    method_name = models.CharField(max_length=100)
    description = models.TextField(max_length=MAX_DESCRIPTION_LEN)

    last_run_time = models.DateTimeField(blank=True, null=True)
    execution_time = models.FloatField(blank=True, null=True)
    status = enumfields.EnumIntegerField(Status, default=Status.UNINITIALIZED)
    num_passing = models.PositiveIntegerField(blank=True, null=True)
    num_na = models.PositiveIntegerField(blank=True, null=True)

    class Meta:
        index_together = ("app_label", "model_name", "method_name")
        unique_together = ("app_label", "model_name", "method_name")
        ordering = ("app_label", "model_name", "method_name")

    def __str__(self):
        return f"{self.model_name}.{self.method_name}: {self.status.name}"

    def get_num_failing(self):
        return self.failing_objects.count()

    def get_num_allowed_to_fail(self):
        return self.failing_objects.filter(allowed_to_fail=True).count()

    @classmethod
    def get_status_for_model(cls, model: Type[models.Model]) -> Status:
        """ return the datavalidation status for the model """
        app_label = model._meta.app_label
        model_name = model.__name__
        statuses = cls.objects \
                      .filter(app_label=app_label, model_name=model_name) \
                      .values_list("status", flat=True)
        model_status: Status = Status.UNINITIALIZED
        for status in statuses:
            if status == Status.PASSING and model_status == Status.UNINITIALIZED:
                model_status = Status.PASSING
            elif status == Status.FAILING:
                model_status = Status.FAILING
            if status == Status.EXCEPTION:
                return Status.EXCEPTION
        return model_status
class Character(models.Model):
    # Fields
    user = models.ForeignKey(User, unique=False, on_delete=models.CASCADE)
    name = models.CharField(max_length=25)
    party = models.ForeignKey(party.Party, unique=False, on_delete=models.CASCADE)

    class_enum = enumfields.EnumIntegerField(classes.Classes,
                                             verbose_name='Class',
                                             default=classes.Classes.paladin)
    head_enum = enumfields.EnumIntegerField(items.Heads,
                                            verbose_name='Head',
                                            default=items.Heads.empty)
    neck_enum = enumfields.EnumIntegerField(items.Necks,
                                            verbose_name='Neck',
                                            default=items.Necks.empty)
    chest_enum = enumfields.EnumIntegerField(items.Chests,
                                             verbose_name='Chest',
                                             default=items.Chests.empty)
    shield_enum = enumfields.EnumIntegerField(items.Shields,
                                              verbose_name='Shield',
                                              default=items.Shields.empty)
    right_hand_enum = enumfields.EnumIntegerField(items.Hands,
                                                  verbose_name='Right Hand',
                                                  default=items.Hands.empty)
    left_hand_enum = enumfields.EnumIntegerField(items.Hands,
                                                 verbose_name='Left Hand',
                                                 default=items.Hands.empty)
    feet_enum = enumfields.EnumIntegerField(items.Feets,
                                            verbose_name='Feet',
                                            default=items.Feets.empty)
    weapon_enum = enumfields.EnumIntegerField(items.Weapons,
                                              verbose_name='Weapon',
                                              default=items.Weapons.empty)

    assigned_ath = models.PositiveIntegerField(verbose_name='Assigned ATH', default=0)
    assigned_ste = models.PositiveIntegerField(verbose_name='Assigned STE', default=0)
    assigned_for = models.PositiveIntegerField(verbose_name='Assigned FOR', default=0)
    assigned_apt = models.PositiveIntegerField(verbose_name='Assigned APT', default=0)
    assigned_per = models.PositiveIntegerField(verbose_name='Assigned PER', default=0)
    assigned_spe = models.PositiveIntegerField(verbose_name='Assigned SPE', default=0)

    # Class constants
    ap_lvl_mod = 2
    hp_lvl_con_mod = 1.5
    mp_lvl_int_mod = 1
    sp_lvl_int_mod = 1
    starting_mdef = 5
    pred_con_mod = 0.5
    mred_int_mod = 0.5
    rd_char_mod = 0.25
    speed_dex_mod = 0.5
    vis_con_mod = 0.5
    extra_max_sp_per_skill = 3
    light_weapon_str_damage_mod = 0.5
    medium_weapon_str_damage_mod = 1.0
    heavy_weapon_str_damage_mod = 1.5
    cha_buy_mod = 7
    """Percent."""

    base_sel = 50
    int_sel_mod = 10
    """Percent."""

    def __str__(self):
        return f'{self.name}: LVL {self.lvl} {self.cls.name}'

    @property
    def cls(self) -> class_type.Class:
        return classes.classes[self.class_enum]

    @property
    def head(self) -> equipment.Wearable:
        return items.heads[self.head_enum]

    @property
    def neck(self) -> equipment.Wearable:
        return items.necks[self.neck_enum]

    @property
    def chest(self) -> equipment.Wearable:
        return items.chests[self.chest_enum]

    @property
    def shield(self) -> equipment.Wearable:
        return items.shields[self.shield_enum]

    @property
    def right_hand(self) -> equipment.Hand:
        return items.hands[self.right_hand_enum]

    @property
    def left_hand(self) -> equipment.Hand:
        return items.hands[self.left_hand_enum]

    @property
    def feet(self) -> equipment.Wearable:
        return items.feets[self.feet_enum]

    @property
    def weapon(self) -> equipment.Weapon:
        return items.weapons[self.weapon_enum]

    @property
    def inventory_items(self) -> Tuple[equipment.Item, ...]:
        return tuple([inventory_slot.item for inventory_slot in self.inventoryslot_set.all()])

    @property
    def utilities(self) -> Tuple[equipment.Utility, ...]:
        utilities = []
        for item in self.inventory_items:
            if isinstance(item, equipment.Utility):
                if self.get_attribute(item.min_attribute) >= item.min_attribute_value:
                    utilities.append(item)
        return tuple(utilities)

    @property
    def wearables(self) -> Tuple[equipment.Wearable, ...]:
        return (self.head, self.neck, self.chest, self.shield, self.right_hand, self.left_hand,
                self.feet, self.weapon)

    @property
    def lvl(self):
        return self.levelup_set.count()

    def get_attribute(self, attribute: Attribute) -> int:
        if attribute is Attribute.stren:
            return self.stren
        elif attribute is Attribute.dex:
            return self.dex
        elif attribute is Attribute.con:
            return self.con
        elif attribute is Attribute.intel:
            return self.intel
        elif attribute is Attribute.wis:
            return self.wis
        elif attribute is Attribute.cha:
            return self.cha

    @property
    def stren(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.stren for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.stren
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.str for wearable in self.wearables]))

    @property
    def dex(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.dex for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.dex
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.dex for wearable in self.wearables]))

    @property
    def con(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.con for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.con
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.con for wearable in self.wearables]))

    @property
    def intel(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.intel for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.intel
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.int for wearable in self.wearables]))

    @property
    def wis(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.wis for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.wis
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.wis for wearable in self.wearables]))

    @property
    def cha(self) -> int:
        return (
            sum([level_up.ad_roll == Attribute.cha for level_up in self.levelup_set.all()]) +
            sum([level_up.selected_attribute == Attribute.cha
                 for level_up in self.levelup_set.all()]) +
            sum([wearable.cha for wearable in self.wearables]))

    @property
    def ap_formula(self) -> str:
        return (f'{self.cls.starting_ap}[Starting AP] + ({self.ap_lvl_mod} * {self.lvl}[LVL]) + '
                f'{self.wis}[WIS] + {self.cha}[CHA] + '
                f'{sum([wearable.ap for wearable in self.wearables])}[Wearables]')

    @property
    def ap(self) -> int:
        return (self.cls.starting_ap + (self.ap_lvl_mod * self.lvl) + self.wis + self.cha +
                sum([wearable.ap for wearable in self.wearables]))

    @property
    def available_ap(self) -> int:
        return self.ap - self.unlockedability_set.count()

    @property
    def unlocked_abilities(self) -> Tuple[ability.Ability, ...]:
        return tuple([unlocked_ability.ability
                      for unlocked_ability in self.unlockedability_set.all()])

    @property
    def available_to_unlock_abilities(self) -> Tuple[ability.Ability, ...]:
        available_abilities = []
        unlocked_abilities = self.unlocked_abilities  # Avoid multiple database reads.
        for class_ability in self.cls.abilities:
            is_available = True
            for prerequisite in class_ability.prerequisites:
                if prerequisite not in unlocked_abilities:
                    is_available = False
            if is_available:
                available_abilities.append(class_ability)
        return tuple(available_abilities)

    @property
    def class_combos(self) -> Tuple[combos.Combo, ...]:
        # TODO: Make this part of cls?  Import issues.
        character_combos = []
        for combo in combos.combos:
            if self.cls.__class__ in combo.classes:
                character_combos.append(combo)
        return tuple(character_combos)

    @property
    def party_members(self) -> Tuple['Character', ...]:
        """Other Characters other than this one in the Party."""
        party_members = []
        for party_member in self.party.character_set.all():
            if party_member != self:
                party_members.append(party_member)
        return tuple(party_members)

    @property
    def party_combos(self) -> Tuple[combos.Combo, ...]:
        character_party_combos = []
        for combo in self.class_combos:
            for party_member in self.party_members:
                if ((self.cls.__class__ is combo.classes[0] and
                     party_member.cls.__class__ is combo.classes[1]) or
                    (self.cls.__class__ is combo.classes[1] and
                     party_member.cls.__class__ is combo.classes[0])):
                    character_party_combos.append(combo)
                    continue
        return tuple(character_party_combos)

    @property
    def unlocked_combos(self) -> Tuple[combos.Combo, ...]:
        unlocked_combos = []
        for combo in self.party_combos:
            if self.lvl >= combo.prerequisite_lvl:
                unlocked_combos.append(combo)
        return tuple(unlocked_combos)

    @property
    def hp_formula(self) -> str:
        return (f'({self.lvl}[LVL] * {self.hp_lvl_con_mod} * {self.con}[CON]) + '
                f'{sum([wearable.hp for wearable in self.wearables])}[Wearables] + '
                f'{sum(level_up.hd_roll for level_up in self.levelup_set.all())}[HD rolls]')

    @property
    def hp(self) -> int:
        return round_up(self.lvl * self.hp_lvl_con_mod * self.con +
                        sum([wearable.hp for wearable in self.wearables]) +
                        sum(level_up.hd_roll for level_up in self.levelup_set.all()))

    @property
    def mp_formula(self) -> str:
        return (f'({self.lvl}[LVL] * {self.mp_lvl_int_mod} * {self.intel}[INT]) + '
                f'{sum([wearable.mp for wearable in self.wearables])}[Wearables] + '
                f'{sum(level_up.md_roll for level_up in self.levelup_set.all())}[MD rolls]')

    @property
    def mp(self) -> int:
        return ((self.lvl * self.mp_lvl_int_mod * self.intel) +
                sum([wearable.mp for wearable in self.wearables]) +
                sum(level_up.md_roll for level_up in self.levelup_set.all()))

    @property
    def sp_formula(self) -> str:
        return (f'({self.lvl}[LVL] * {self.mp_lvl_int_mod} * {self.intel}[INT]) + '
                f'{sum([wearable.sp for wearable in self.wearables])}[Wearables] + '
                f'{sum(level_up.sd_roll for level_up in self.levelup_set.all())}[SD rolls]')

    @property
    def sp(self) -> int:
        return (self.lvl * self.sp_lvl_int_mod * self.intel +
                sum([wearable.sp for wearable in self.wearables]) +
                sum(level_up.sd_roll for level_up in self.levelup_set.all()))

    @property
    def available_sp(self) -> int:
        return (self.sp - self.assigned_ath - self.assigned_ste - self.assigned_apt -
                self.assigned_for - self.assigned_per - self.assigned_spe)

    @property
    def max_sp_per_skill_formula(self) -> str:
        return f'{self.lvl}[LVL] + {self.extra_max_sp_per_skill}'

    @property
    def max_sp_per_skill(self) -> int:
        return self.lvl + self.extra_max_sp_per_skill

    @property
    def pdef_formula(self) -> str:
        return (f'{self.cls.pdef}[Class PDEF] + {self.dex}[DEX] + '
                f'{sum([wearable.pdef for wearable in self.wearables])}[Wearables]')

    @property
    def pdef(self) -> int:
        return self.cls.pdef + self.dex + sum([wearable.pdef for wearable in self.wearables])

    @property
    def mdef_formula(self) -> str:
        return (f'{self.starting_mdef}[Starting MDEF] + '
                f'({self.cls.mdef}[Class MDEF] * {self.lvl}[LVL]) + {self.wis}[WIS] + '
                f'{sum([wearable.mdef for wearable in self.wearables])}[Wearables]')

    @property
    def mdef(self) -> int:
        return round_up(self.starting_mdef + (self.cls.mdef * self.lvl) + self.wis +
                        sum([wearable.mdef for wearable in self.wearables]))

    @property
    def pred_formula(self) -> str:
        return (f'{self.cls.pred}[Class PRED] + ({self.pred_con_mod} * {self.con}[CON]) + '
                f'{sum([wearable.pred for wearable in self.wearables])}[Wearables]')

    @property
    def pred(self) -> int:
        return round_up(self.cls.pred + (self.pred_con_mod * self.con) +
                        sum([wearable.pred for wearable in self.wearables]))

    @property
    def mred_formula(self) -> str:
        return (f'{self.cls.mred}[Class MRED] + ({self.mred_int_mod} * {self.intel}[INT]) + '
                f'{sum([wearable.mred for wearable in self.wearables])}[Wearables]')

    @property
    def mred(self) -> int:
        return round_up(self.cls.mred + (self.mred_int_mod * self.intel) +
                        sum([wearable.mred for wearable in self.wearables]))

    @property
    def reg_formula(self) -> str:
        return (f'({self.cls.reg}[Class REG] * {self.lvl}[LVL]) + {self.cha}[CHA] + '
                f'{sum([wearable.reg for wearable in self.wearables])}[Wearables]')

    @property
    def reg(self) -> int:
        return round_up((self.cls.reg * self.lvl) + self.cha +
                        sum([wearable.reg for wearable in self.wearables]))

    @property
    def rd_formula(self) -> str:
        return (f'LVL 1-3=d2, LVL 4-6=d4, LVL 7-9=d6, LVL 10-12=d8, LVL 13-15=d10, LVL 16+=d12\n'
                f'({self.rd_char_mod} * {self.cha}[CHA]) + '
                f'{sum([wearable.rd for wearable in self.wearables])}[Wearables]')

    @property
    def rd(self) -> dice.DiceFormula:
        rd_modifier = round_up((self.rd_char_mod * self.cha) +
                               sum([wearable.rd for wearable in self.wearables]))
        if self.lvl <= 3:
            reg_dice = dice.Dice.from_str('d2')
        elif 4 <= self.lvl <= 6:
            reg_dice = dice.Dice.from_str('d4')
        elif 7 <= self.lvl <= 9:
            reg_dice = dice.Dice.from_str('d6')
        elif 10 <= self.lvl <= 12:
            reg_dice = dice.Dice.from_str('d8')
        elif 13 <= self.lvl <= 15:
            reg_dice = dice.Dice.from_str('d10')
        else:
            reg_dice = dice.Dice.from_str('d12')

        return dice.DiceFormula(dice_pool=(reg_dice,), modifier=rd_modifier)

    @property
    def speed_formula(self) -> str:
        return (f'{self.cls.speed}[Class SPEED] + ({self.speed_dex_mod} * {self.dex}[DEX]) + '
                f'{sum([wearable.speed for wearable in self.wearables])}[Wearables]')

    @property
    def speed(self) -> int:
        return round_up(self.cls.speed + (self.speed_dex_mod * self.dex) +
                        sum([wearable.speed for wearable in self.wearables]))

    @property
    def vis_formula(self) -> str:
        return (f'{self.cls.vis}[Class VIS] + ({self.vis_con_mod} * {self.con}[CON]) + '
                f'{sum([wearable.vis for wearable in self.wearables])}[Wearables]')

    @property
    def vis(self) -> int:
        return round_up(self.cls.vis + (self.vis_con_mod * self.con) +
                        sum([wearable.vis for wearable in self.wearables]))

    @property
    def bpac_formula(self) -> str:
        return (f'({self.cls.pac}[Class PAC] * {self.lvl}[LVL]) + {self.stren}[STR] + '
                f'{sum([wearable.bpac for wearable in self.wearables])}[Wearables]')

    @property
    def bpac(self) -> int:
        return round_up((self.cls.pac * self.lvl) + self.stren +
                        sum([wearable.bpac for wearable in self.wearables]))

    @property
    def bmac_formula(self) -> str:
        return (f'({self.cls.mac}[Class MAC] * {self.lvl}[LVL]) + {self.cha}[CHA] + '
                f'{sum([wearable.bmac for wearable in self.wearables])}[Wearables]')

    @property
    def bmac(self) -> int:
        return round_up((self.cls.mac * self.lvl) + self.cha +
                        sum([wearable.bmac for wearable in self.wearables]))

    @property
    def cran(self) -> int:
        return sum([wearable.cran for wearable in self.wearables])

    @property
    def ath_formula(self) -> str:
        return (f'({self.cls.ath}[Class ATH] * {self.stren}[STR]) + '
                f'{self.assigned_ath}[Assigned ATH] + '
                f'{sum([wearable.ath for wearable in self.wearables])}[Wearables]')

    @property
    def ath(self) -> int:
        return ((self.cls.ath * self.stren) + self.assigned_ath +
                sum([wearable.ath for wearable in self.wearables]))

    @property
    def ste_formula(self) -> str:
        return (f'({self.cls.ste}[Class STE] * {self.dex}[DEX]) + '
                f'{self.assigned_ste}[Assigned STE] + '
                f'{sum([wearable.ste for wearable in self.wearables])}[Wearables]')

    @property
    def ste(self) -> int:
        return ((self.cls.ste * self.dex) + self.assigned_ste +
                sum([wearable.ste for wearable in self.wearables]))

    @property
    def for_formula(self) -> str:
        return (f'({self.cls.fort}[Class FOR] * {self.con}[CON]) + '
                f'{self.assigned_for}[Assigned FOR] + '
                f'{sum([wearable.fort for wearable in self.wearables])}[Wearables]')

    @property
    def fort(self) -> int:
        return ((self.cls.fort * self.con) + self.assigned_for +
                sum([wearable.fort for wearable in self.wearables]))

    @property
    def apt_formula(self) -> str:
        return (f'({self.cls.apt}[Class APT] * {self.intel}[INT]) + '
                f'{self.assigned_apt}[Assigned APT] + '
                f'{sum([wearable.apt for wearable in self.wearables])}[Wearables]')

    @property
    def apt(self) -> int:
        return ((self.cls.apt * self.intel) + self.assigned_apt +
                sum([wearable.apt for wearable in self.wearables]))

    @property
    def per_formula(self) -> str:
        return (f'({self.cls.per}[Class PER] * {self.wis}[WIS]) + '
                f'{self.assigned_per}[Assigned PER] + '
                f'{sum([wearable.per for wearable in self.wearables])}[Wearables]')

    @property
    def per(self) -> int:
        return ((self.cls.per * self.wis) + self.assigned_per +
                sum([wearable.per for wearable in self.wearables]))

    @property
    def spe_formula(self) -> str:
        return (f'({self.cls.spe}[Class SPE] * {self.cha}[CHA]) + '
                f'{self.assigned_spe}[Assigned SPE] + '
                f'{sum([wearable.spe for wearable in self.wearables])}[Wearables]')

    @property
    def spe(self) -> int:
        return ((self.cls.spe * self.cha) + self.assigned_spe +
                sum([wearable.spe for wearable in self.wearables]))

    @property
    def buy_formula(self) -> str:
        return f'{self.cha_buy_mod} * {self.cha}[CHA]'

    @property
    def buy(self) -> int:
        return min(self.cha_buy_mod * self.cha, 100)

    @property
    def buy_fraction(self) -> float:
        """Returns a value that can be multiplied by a cost to get the cost of an item for
        this character."""
        return 1.0 - (self.buy / 100)

    @property
    def sel_formula(self) -> str:
        return f'{self.base_sel}[Base SEL] + ({self.int_sel_mod} * {self.intel}[INT])'

    @property
    def sel(self) -> int:
        return min(self.base_sel + self.int_sel_mod * self.intel, 100)

    @property
    def sel_fraction(self) -> float:
        """Returns a value that can be multiplied by a cost to get the SEL value of an item for
        this character."""
        return self.sel / 100

    @property
    def vul_set(self) -> equipment.VulnerabilitySet:
        vul_set = equipment.VulnerabilitySet()

        for wearable in self.wearables:
            vul_set.merge(wearable.vul_set)

        return vul_set

    @property
    def can_use_weapon(self) -> bool:
        if self.weapon.style is equipment.Style.melee:
            if self.weapon.type is equipment.Type.light:
                return self.cls.use_melee_light
            elif self.weapon.type is equipment.Type.medium:
                return self.cls.use_melee_medium
            elif self.weapon.type is equipment.Type.heavy:
                return self.cls.use_melee_heavy
        elif self.weapon.style is equipment.Style.ranged:
            if self.weapon.type is equipment.Type.light:
                return self.cls.use_ranged_light
            elif self.weapon.type is equipment.Type.medium:
                return self.cls.use_ranged_medium
            elif self.weapon.type is equipment.Type.heavy:
                return self.cls.use_ranged_heavy
        elif self.weapon.style is equipment.Style.magic:
            if self.weapon.type is equipment.Type.light:
                return self.cls.use_magic_light
            elif self.weapon.type is equipment.Type.medium:
                return self.cls.use_magic_medium
            elif self.weapon.type is equipment.Type.heavy:
                return self.cls.use_magic_heavy

    def can_use_wearable(self, wearable: equipment.Wearable) -> bool:
        if wearable.type is equipment.Type.light and self.cls.use_light_armor:
            return True
        elif wearable.type is equipment.Type.medium and self.cls.use_medium_armor:
            return True
        elif wearable.type is equipment.Type.heavy and self.cls.use_heavy_armor:
            return True
        else:
            return False

    @property
    def _str_damage(self) -> int:
        str_damage = 0
        if self.weapon.type is equipment.Type.light:
            str_damage = round_up(self.light_weapon_str_damage_mod * self.stren)
        elif self.weapon.type is equipment.Type.medium:
            str_damage = round_up(self.medium_weapon_str_damage_mod * self.stren)
        elif self.weapon.type is equipment.Type.heavy:
            str_damage = round_up(self.heavy_weapon_str_damage_mod * self.stren)
        return str_damage

    @property
    def weapon_pdam(self) -> Optional[dice.DiceFormula]:
        if self.weapon.pdam is None:
            return None
        else:
            pdam_dice = copy.deepcopy(self.weapon.pdam)
            pdam_dice.modifier += self._str_damage
            return pdam_dice

    @property
    def weapon_pdam_dps(self) -> int:
        if self.weapon_pdam is not None:
            return round(self.weapon.attacks * self.weapon_pdam.mean(), 1)
        else:
            return 0

    @property
    def weapon_mdam(self) -> Optional[dice.DiceFormula]:
        if self.weapon.mdam is None:
            return None
        else:
            mdam_dice = copy.deepcopy(self.weapon.mdam)
            mdam_dice.modifier += self._str_damage
            return mdam_dice

    @property
    def weapon_mdam_dps(self) -> int:
        if self.weapon_mdam is not None:
            return round(self.weapon.attacks * self.weapon_mdam.mean(), 1)
        else:
            return 0
class FeetForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Feets,
                                            verbose_name='Feet').formfield()
class HandForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Hands,
                                            verbose_name='Hand').formfield()
class ShieldForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Shields,
                                            verbose_name='Shield').formfield()
class ChestForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Chests,
                                            verbose_name='Chest').formfield()
class NeckForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Necks,
                                            verbose_name='Neck').formfield()
class WeaponForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Weapons,
                                            verbose_name='Weapon').formfield()
class UtilityForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(
        items.Utilities, verbose_name='Utility').formfield()
class ItemForm(forms.Form):
    item_enum = enumfields.EnumIntegerField(items.Items,
                                            verbose_name='Item').formfield()