示例#1
0
class Guild(Model):
    guild_id = BigIntField(unique=True)
    prefix = CharField(max_length=5, null=True, default="?")
    clear_spam = BooleanField(default=False)
    aggregate_clans = BooleanField(default=True)
    track_sherpas = BooleanField(default=False)
    admin_channel = BigIntField(unique=True, null=True)
    announcement_channel = BigIntField(unique=True, null=True)
示例#2
0
class MonsterDrop(Model):
    item = ForeignKeyField("models.Item", related_name="drops")
    monster = ForeignKeyField("models.Monster", related_name="drops")

    rate = IntField()
    pickpocket_only = BooleanField(default=False)
    no_pickpocket = BooleanField(default=False)
    conditional = BooleanField(default=False)
    fixed = BooleanField(default=False)
    stealable_accordion = BooleanField(default=False)
示例#3
0
class Skill(Model, metaclass=SkillMeta):
    id = IntField(pk=True, generated=False)
    name = CharField(max_length=255)
    image = CharField(max_length=255)
    level_required = IntField(default=0)
    mp_cost = IntField(default=0)

    passive: bool = BooleanField(default=False)  # type: ignore
    noncombat: bool = BooleanField(default=False)  # type: ignore
    shruggable: bool = BooleanField(default=False)  # type: ignore
    combat: bool = BooleanField(default=False)  # type: ignore
    healing: bool = BooleanField(default=False)  # type: ignore
    summon: bool = BooleanField(default=False)  # type: ignore
    expression: bool = BooleanField(default=False)  # type: ignore
    walk: bool = BooleanField(default=False)  # type: ignore
    mutex_song: bool = BooleanField(default=False)  # type: ignore

    @property
    def buff(self) -> bool:
        return self.shruggable

    def have(self):
        return self in self.kol.state.skills

    async def cast(self, times: int = 1):
        return await request.skill_use(self.kol, self, times).parse()
示例#4
0
class User(Model):
    id = UUIDField(pk=True, index=True)

    # 0 == Free, 10 == Premium
    tier = IntField(default=0)

    username = CharField(max_length=255, unique=True, index=True)
    hashed_password = TextField(null=False)

    encrypted = BooleanField(default=False)
    admin = BooleanField(default=False)

    journals: ReverseRelation["Journal"]
示例#5
0
class ClanMember(Model):
    platform_id = IntField()
    join_date = DatetimeField()
    is_active = BooleanField(default=True)
    last_active = DatetimeField(null=True)
    is_sherpa = BooleanField(default=False)
    member_type = IntField(null=True, validators=[ClanMemberRankValidator()])

    clan: ForeignKeyRelation[Clan] = ForeignKeyField(
        "seraphsix.Clan", related_name="members", to_field="id"
    )

    member: ForeignKeyRelation[Member] = ForeignKeyField(
        "seraphsix.Member", related_name="clans", to_field="id"
    )
示例#6
0
class Role(Model):
    role_id = BigIntField()
    platform_id = IntField(null=True)
    is_sherpa = BooleanField(null=True)
    is_clanmember = BooleanField(null=True)
    is_new_clanmember = BooleanField(null=True)
    is_non_clanmember = BooleanField(null=True)
    is_protected_clanmember = BooleanField(null=True)

    guild: ForeignKeyRelation[Guild] = ForeignKeyField(
        "seraphsix.Guild", related_name="roles", to_field="id"
    )

    class Meta:
        indexes = ("guild", "role_id")
示例#7
0
class Dataset(Model):
    id = IntField(pk=True)

    collection = ForeignKeyField('models.Collection', related_name='datasets')
    discarded = BooleanField(default=False)
    name = TextField()
    status = IntField(default=0)
    time_added = IntField()  # ms since epoch
    timestamp = IntField()  # ms since epoch

    setid = custom.SetIDField(unique=True)
    tags = ManyToManyField('models.Tag', related_name='datasets')
    acn = ForeignKeyField('models.Acn',
                          related_name='datasets',
                          on_delete=RESTRICT)

    # Populated by backreferences: comments, files

    error = make_status_property(1)
    missing = make_status_property(2)
    outdated = make_status_property(4)
    pending = make_status_property(8)

    def __repr__(self):
        return f'<{type(self).__name__} {self.setid} {self.name}>'
示例#8
0
class Guild(Model):
    id = BigIntField(pk=True, generated=False)
    mute_role = BigIntField(null=True)
    mod_logs = BigIntField(null=True)
    mod_users = ArrayField(int, default=list)
    mod_roles = ArrayField(int, default=list)
    disabled_commands = ArrayField(str, default=list)
    disabled_channels = ArrayField(int, default=list)
    disabled_users = ArrayField(int, default=list)
    ignored_users = disabled_users = ArrayField(int)
    ignored_channels = disabled_users = ArrayField(int)
    tags_locked = BooleanField(defualt=False)
    tags_mod_only = BooleanField(defualt=False)
    language = CharField(max_length=20, null=False, default="en")

    # I am related stuff:
    iam_roles = ArrayField(int, null=True)
    iam_disabled_users = ArrayField(int, null=True)
示例#9
0
class User(Model):
    id = IntField(pk=True)
    username = CharField(20, unique=True)
    password_hash = BinaryField()
    is_admin = BooleanField(default=False)

    def check_password(self, to_check: str) -> bool:
        return check_password_hash(self.password_hash.decode(), to_check)

    def set_password(self, new_password: str):
        self.password_hash = generate_password_hash(new_password).encode()
示例#10
0
class File(Model):
    id = IntField(pk=True)
    dataset = ForeignKeyField('models.Dataset', related_name='files')
    idx = IntField()  # files are counted per dataset

    missing = BooleanField(default=False)
    mtime = IntField()  # ms since epoch
    path = TextField()
    size = IntField()

    def __repr__(self):
        return f"<{type(self).__name__} '{self.path}'>"
示例#11
0
class User(Model):
    id = IntField(pk=True)
    name = CharField(max_length=255, unique=True)
    password = TextField(null=True)
    given_name = TextField(null=True)
    family_name = TextField(null=True)
    email = TextField(null=True)
    realm = TextField()
    realmuid = TextField(null=True)
    active = BooleanField()
    time_created = DatetimeField(auto_now_add=True)
    time_updated = DatetimeField(auto_now=True)
    groups = ManyToManyField('models.Group', related_name='users')
示例#12
0
class Clan(Model):
    clan_id = BigIntField(unique=True)
    name = CharField(max_length=255)
    callsign = CharField(max_length=4)
    platform = IntField(null=True, validators=[PlatformValidator()])
    the100_group_id = IntField(unique=True, null=True)
    activity_tracking = BooleanField(default=True)

    guild: ForeignKeyRelation[Guild] = ForeignKeyField(
        "seraphsix.Guild", related_name="clans", to_field="id"
    )

    members: ReverseRelation["ClanMember"]
示例#13
0
class Guild(Model):
    id = BigIntField(pk=True)
    prefix = TextField(null=True)
    mute_role = BigIntField(null=True)
    level_up_messages = BooleanField(default=True)
    moderators: ReverseRelation["Moderator"]
    mutes: ReverseRelation["Mute"]
    warns: ReverseRelation["Warn"]

    class Meta:
        table = "guilds"

    def __str__(self):
        return f"<Guild id:{self.id} prefix:{self.prefix} muterole:{self.mute_role}>"
示例#14
0
class Modifier(Model):
    item = ForeignKeyField("models.Item", related_name="modifiers", null=True)
    item_id: Optional[int]

    effect = ForeignKeyField("models.Effect",
                             related_name="modifiers",
                             null=True)
    effect_id: Optional[int]

    key = CharField(max_length=255)
    numeric_value = IntField(null=True)
    string_value = CharField(max_length=255, null=True)
    expression_value = CharField(max_length=255, null=True)
    percentage = BooleanField(default=False)
示例#15
0
文件: models.py 项目: ahridin/stats
class ApiJob(Model):
    """API job model."""

    requestor: ForeignKeyRelation[ApiUser] = ForeignKeyField(
        "models.ApiUser", related_name="jobs")
    request_time = DatetimeField(auto_now=True)
    complete_time = DatetimeField(null=True)
    in_progress = BooleanField(default=False)
    detail = TextField(null=True)

    class Meta:
        """Tortoise ORM Config."""

        table = "api_jobs"
示例#16
0
class GameMember(Model):
    time_played = FloatField(null=True)
    completed = BooleanField(null=True)

    member: ForeignKeyRelation[Member] = ForeignKeyField(
        "seraphsix.Member", related_name="games", to_field="id"
    )

    game: ForeignKeyRelation[Game] = ForeignKeyField(
        "seraphsix.Game", related_name="members", to_field="id"
    )

    class Meta:
        indexes = ("member", "game")
示例#17
0
class ClanMemberApplication(Model):
    approved = BooleanField(default=False)
    message_id = BigIntField(unique=True)

    guild: ForeignKeyRelation[Guild] = ForeignKeyField(
        "seraphsix.Guild", related_name="clanmemberapplications", to_field="id"
    )

    member: ForeignKeyRelation[Member] = ForeignKeyField(
        "seraphsix.Member", related_name="clanmemberapplications_created", to_field="id"
    )

    approved_by: ForeignKeyRelation[Member] = ForeignKeyField(
        "seraphsix.Member",
        related_name="clanmemberapplications_approved",
        to_field="id",
    )
示例#18
0
class Mute(Model):
    id = IntField(pk=True)
    moderator = BigIntField()
    reason = TextField(null=True)
    start = DatetimeField(auto_now_add=True)
    end = DatetimeField()
    active = BooleanField(default=True)
    user: ForeignKeyRelation[User] = ForeignKeyField("models.User",
                                                     related_name="mutes")
    guild: ForeignKeyRelation[Guild] = ForeignKeyField("models.Guild",
                                                       related_name="mutes")

    class Meta:
        table = "mutes"

    def __str__(self):
        return (
            f"<Mute id:{self.id} moderator:{self.moderator} "
            f"reason:'{self.reason}' start:{self.start} end:{self.end} "
            f"active:{self.active} user:{self.user.id} guild:{self.guild.id}>")
示例#19
0
class Member(Model):
    discord_id = BigIntField(null=True)
    bungie_id = BigIntField(null=True)
    bungie_username = CharField(max_length=255, null=True)
    xbox_id = BigIntField(null=True)
    xbox_username = CharField(max_length=255, unique=True, null=True)
    psn_id = BigIntField(null=True)
    psn_username = CharField(max_length=255, unique=True, null=True)
    blizzard_id = BigIntField(null=True)
    blizzard_username = CharField(max_length=255, unique=True, null=True)
    steam_id = BigIntField(null=True)
    steam_username = CharField(max_length=255, unique=True, null=True)
    stadia_id = BigIntField(null=True)
    stadia_username = CharField(max_length=255, unique=True, null=True)
    the100_id = BigIntField(unique=True, null=True)
    the100_username = CharField(max_length=255, unique=True, null=True)
    timezone = CharField(max_length=255, null=True)
    bungie_access_token = CharField(max_length=360, unique=True, null=True)
    bungie_refresh_token = CharField(max_length=360, unique=True, null=True)
    is_cross_save = BooleanField(default=False)
    primary_membership_id = BigIntField(unique=True, null=True)

    clan: ReverseRelation["ClanMember"]
    games: ReverseRelation["GameMember"]

    class Meta:
        indexes = [
            PostgreSQLIndex(
                fields={
                    "discord_id",
                    "bungie_id",
                    "xbox_id",
                    "psn_id",
                    "blizzard_id",
                    "steam_id",
                    "stadia_id",
                    "the100_id",
                }
            )
        ]
示例#20
0
文件: Item.py 项目: danheath/libkol
class Item(Model, metaclass=ItemMeta):
    id = IntField()
    name = CharField(max_length=255)
    desc_id = IntField()
    plural = CharField(max_length=255, null=True)
    image = CharField(max_length=255)
    autosell = IntField(default=0)
    level_required = IntField(default=0)  # Level required

    # Consumables
    food = BooleanField(default=False)
    fullness = IntField(default=0)
    booze = BooleanField(default=False)
    inebriety = IntField(default=0)
    spleen = BooleanField(default=False)
    spleenhit = IntField(default=0)
    quality = CharField(max_length=255, null=True)
    gained_adventures_min = IntField(default=0)
    gained_adventures_max = IntField(default=0)
    gained_muscle_min = IntField(default=0)
    gained_muscle_max = IntField(default=0)
    gained_mysticality_min = IntField(default=0)
    gained_mysticality_max = IntField(default=0)
    gained_moxie_min = IntField(default=0)
    gained_moxie_max = IntField(default=0)

    # Usability
    usable = BooleanField(default=False)
    multiusable = BooleanField(default=False)
    combat_usable = BooleanField(default=False)
    reusable = BooleanField(default=False)
    combat_reusable = BooleanField(default=False)
    curse = BooleanField(default=False)  # Can be used on others

    # Equipment
    hat = BooleanField(default=False)
    pants = BooleanField(default=False)
    shirt = BooleanField(default=False)
    weapon = BooleanField(default=False)
    weapon_hands = IntField(null=True)
    weapon_type = CharField(max_length=255, null=True)
    offhand = BooleanField(default=False)
    offhand_type = CharField(max_length=255, null=True)
    accessory = BooleanField(default=False)
    container = BooleanField(default=False)
    sixgun = BooleanField(default=False)
    familiar_equipment = BooleanField(default=False)
    power = IntField(null=True)
    required_muscle = IntField(default=0)
    required_mysticality = IntField(default=0)
    required_moxie = IntField(default=0)

    # Collections
    foldgroup = ForeignKeyField("models.FoldGroup",
                                related_name="items",
                                null=True)
    foldgroup_id: Optional[int]
    zapgroup = ForeignKeyField("models.ZapGroup",
                               related_name="items",
                               null=True)
    zapgroup_id: Optional[int]

    # NPC Store Info
    store_row = IntField(null=True)
    store_price = IntField(null=True)
    store = ForeignKeyField("models.Store", related_name="items", null=True)
    store_id: Optional[int]

    # Flags
    hatchling = BooleanField(default=False)
    pokepill = BooleanField(default=False)
    sticker = BooleanField(default=False)
    card = BooleanField(default=False)
    folder = BooleanField(default=False)
    bootspur = BooleanField(default=False)
    bootskin = BooleanField(default=False)
    food_helper = BooleanField(default=False)
    drink_helper = BooleanField(default=False)
    guardian = BooleanField(default=False)
    bounty = BooleanField(default=False)  # Can appear as a bounty item
    candy = IntField()  # 0: n/a, 1: simple, 2: complex
    sphere = BooleanField(default=False)  # What is this for?
    quest = BooleanField(default=False)  # is a quest item
    gift = BooleanField(default=False)  # is a gift item
    tradeable = BooleanField(default=False)  # is tradeable
    discardable = BooleanField(default=False)  # is discardable

    def pluralize(self):
        return "{}s".format(self.name) if self.plural is None else self.plural

    @classmethod
    async def get_or_discover(cls, *args, **kwargs) -> "Item":
        result = await cls.filter(*args, **kwargs).first()

        if result is None:
            id: int = kwargs.get("id", None)
            desc_id: int = kwargs.get("desc_id", None)

            return await cls.discover(id=id, desc_id=desc_id)

        return result

    @classmethod
    async def discover(cls, id: int = None, desc_id: int = None):
        """
        Discover this item using its id or description id. The description id is preferred as
        it provides more information, so if only an id is provided, libkol will first determine
        the desc_id.

        Note that this Returns an Item object but it is not automatically committed to the database.
        It is not sufficient to run `await item.save()` to do this however as tortoise-orm will attempt to
        `UPDATE` the row because it already has an `id` set. Instead you need to run
        `awaititem._insert_instance()` explicitly.


        :param id: Id of the item to discover
        :param desc_id: Description id of the item to discover
        """
        if id is not None:
            desc_id = (await request.item_information(cls.kol,
                                                      id).parse()).descid

        if desc_id is None:
            raise ItemNotFoundError(
                "Cannot discover an item without either an id or a desc_id")

        info = await request.item_description(cls.kol, desc_id).parse()
        return Item(**{k: v for k, v in info.items() if v is not None})

    async def get_mall_price(self, limited: bool = False) -> int:
        """
        Get the lowest price for this item in the mall

        :param limited: Include limited sales in this search
        """
        prices = await request.mall_price(self.kol, self).parse()

        if limited:
            return prices.limited[0].price

        return prices.unlimited[0].price

    async def get_mall_listings(self, **kwargs) -> List["types.Listing"]:
        return await request.mall_search(self.kol, query=self,
                                         **kwargs).parse()

    async def buy_from_mall(
        self,
        listing: "types.Listing" = None,
        store_id: int = None,
        price: int = 0,
        quantity: int = 1,
    ):
        if listing is None and store_id is None:
            listings = await self.get_mall_listings(num_results=quantity,
                                                    max_price=price)
            tasks = [
                request.mall_purchase(self.kol, item=self, listing=l).parse()
                for l in listings
            ]
            return await asyncio.gather(*tasks)

        return await request.mall_purchase(
            self.kol,
            item=self,
            listing=listing,
            store_id=store_id,
            price=price,
            quantity=quantity,
        ).parse()

    def amount(self):
        return self.kol.state["inventory"][self]

    async def use(self, quantity: int = 1, multi_use: bool = True):
        if self.usable is False:
            raise WrongKindOfItemError("This item cannot be used")

        if self.multiusable and multi_use:
            await request.item_multi_use(self.kol, self, quantity).parse()
            return

        tasks = [
            request.item_use(self.kol, self).parse() for _ in range(quantity)
        ]
        return await asyncio.gather(*tasks)
示例#21
0
class Familiar(Model, metaclass=FamiliarMeta):
    id = IntField(pk=True, generated=False)
    name = CharField(max_length=255)
    image = CharField(max_length=255)

    # Behaviour
    stat_volley = BooleanField(default=False)
    stat_sombrero = BooleanField(default=False)
    item_drop = BooleanField(default=False)
    meat_drop = BooleanField(default=False)
    physical_attack = BooleanField(default=False)
    elemental_attack = BooleanField(default=False)
    drop = BooleanField(default=False)
    block = BooleanField(default=False)
    delevel = BooleanField(default=False)
    combat_hp = BooleanField(default=False)
    combat_mp = BooleanField(default=False)
    combat_meat = BooleanField(default=False)
    combat_stat = BooleanField(default=False)
    combat_other = BooleanField(default=False)
    post_hp = BooleanField(default=False)
    post_mp = BooleanField(default=False)
    post_meat = BooleanField(default=False)
    post_stat = BooleanField(default=False)
    post_other = BooleanField(default=False)
    passive = BooleanField(default=False)
    underwater = BooleanField(default=False)
    variable = BooleanField(default=False)

    # Related items
    hatchling = ForeignKeyField("models.Item",
                                related_name="grows_into",
                                null=True)
    hatchling_id: Optional[int]

    equipment = ForeignKeyField("models.Item",
                                related_name="equipment_for",
                                null=True)
    equipment_id: Optional[int]

    # Arena skills
    cave_match_skill = IntField(default=0)
    scavenger_hunt_skill = IntField(default=0)
    obstacle_course_skill = IntField(default=0)
    hide_and_seek_skill = IntField(default=0)

    # Pokefam
    pokefam = BooleanField(default=False)

    # Attributes
    bites = BooleanField(default=False)
    has_eyes = BooleanField(default=False)
    has_hands = BooleanField(default=False)
    has_wings = BooleanField(default=False)
    is_animal = BooleanField(default=False)
    is_bug = BooleanField(default=False)
    is_flying = BooleanField(default=False)
    is_hot = BooleanField(default=False)
    is_mechanical = BooleanField(default=False)
    is_quick = BooleanField(default=False)
    is_slayer = BooleanField(default=False)
    is_sleazy = BooleanField(default=False)
    is_undead = BooleanField(default=False)
    wears_clothes = BooleanField(default=False)

    def __ge__(self, other):
        if isinstance(other, str):
            return self.name == other
        elif isinstance(other, int):
            return self.id == other
        else:
            return self == other

    @property
    def have(self) -> bool:
        return self in self.kol.familiars

    @property
    def weight(self) -> Optional[int]:
        if self.have is False:
            return None

        return self.kol.familiars[self].weight
示例#22
0
class Trophy(Model):
    id = IntField()
    name = CharField(max_length=255)
    image = CharField(max_length=255)
    before_ascending = BooleanField(default=False)
    stateful = BooleanField(default=False)
示例#23
0
class Monster(Model):
    id = IntField(pk=True, generated=False)
    name = CharField(max_length=255)

    # Flags
    boss = BooleanField(default=False)
    free = BooleanField(default=False)
    nobanish = BooleanField(default=False)
    nocopy = BooleanField(default=False)
    nomanuel = BooleanField(default=False)
    semirare = BooleanField(default=False)
    superlikely = BooleanField(default=False)
    ultrarare = BooleanField(default=False)
    wanderer = BooleanField(default=False)
    nowander = BooleanField(default=False)
    dummy = BooleanField(default=False)
    ghost = BooleanField(default=False)

    # Variable Stats
    _attack = PickleField()
    _cap = PickleField(default=10000)
    _defence = PickleField()
    _experience = PickleField(default=0)
    _floor = PickleField(default=10)
    _hp = PickleField()
    _initiative = PickleField()
    _ml_factor = PickleField(default=1)
    _scale = PickleField(default=0)
    _sprinkle_max = PickleField(default=0)
    _sprinkle_min = PickleField(default=0)

    # Static stats
    attack_element = EnumField(enum_type=Element, null=True)
    defence_element = EnumField(enum_type=Element, null=True)
    meat = IntField(default=0)
    phylum = EnumField(enum_type=Phylum, null=True)
    physical_resistance = IntField(default=0)

    async def get_cap(self) -> int:
        return await expression.evaluate(self.kol, self._cap)

    async def get_floor(self) -> int:
        return await expression.evaluate(self.kol, self._floor)

    async def get_scale(self) -> int:
        return await expression.evaluate(self.kol, self._scale)

    async def get_attack(self) -> int:
        return await expression.evaluate(self.kol, self._attack)

    async def get_defence(self) -> int:
        return await expression.evaluate(self.kol, self._defence)

    async def get_hp(self) -> int:
        if self._hp is not None:
            return max(await expression.evaluate(self.kol, self._hp), 1)

        if self.get_scale() is None:
            return -1

        hp = min(
            self.get_cap(),
            max(self.get_floor(), self.kol.get_stat(Stat.Muscle, buffed=True)),
        )

        return max(hp // (4 / 3), 1)

    @classmethod
    async def identify(cls,
                       name: str,
                       image: Optional[str] = None) -> "Monster":
        if image is not None:
            from .MonsterImage import MonsterImage

            monster_image = await MonsterImage.get(
                image=image).prefetch_related("monster")
            return monster_image.monster

        if name.startswith(("a ", "an")):
            name = name[name.find(" "):]

        return await cls.get(name=name)
示例#24
0
class User(BaseModel):
    """User Model"""

    FIRST_NAME_LENGHT = 20
    LOGIN_LENGHT = 20
    LAST_NAME_LENGHT = 20
    EMAIL_LENGHT = 60

    login = CharField(LOGIN_LENGHT,
                      unique=True,
                      description="The login name of the user.")

    first_name = CharField(FIRST_NAME_LENGHT, null=True)
    last_name = CharField(LAST_NAME_LENGHT, null=True)
    email = CharField(EMAIL_LENGHT, null=True)
    is_active = BooleanField(null=True, default=False)
    is_verified = BooleanField(null=True, default=False)
    verified_at = DatetimeField(null=True)
    password_hash = CharField(256, null=True)
    last_login_at = DatetimeField(null=True)

    roles = ManyToManyField("model.Role",
                            related_name="users",
                            through="user_roles")

    class Meta:
        # pylint: disable=too-few-public-methods
        # pylint: disable=missing-docstring
        table = "user"
        ordering = ["login", "last_name", "first_name"]

    class PydanticMeta:
        include = (
            "id",
            "login",
            "last_login_at",
            "first_name",
            "last_name",
            "verified_at",
            "created_at",
        )

    def __str__(self):
        return "User"

    @property
    def password(self):
        """
        Reading the password is forbidden.
        """
        raise EnvironmentError()

    @property
    def is_password_set(self):
        """
        Checks, if the password has been set.
        """
        return self.password_hash is not None

    @password.setter
    def password(self, password):
        """Hash a password for storing."""
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password: str) -> None:
        """
        Generate a hashed password and compere it with the
        stored password hash.
        """
        if not self.is_password_set:
            return False
        return check_password_hash(self.password_hash, password)
示例#25
0
class Bonus(Model):
    item: Optional["libkol.Item"] = ForeignKeyField("models.Item",
                                                    related_name="bonuses",
                                                    null=True)  # type: ignore
    item_id: Optional[int]

    effect: Optional["libkol.Effect"] = ForeignKeyField(
        "models.Effect", related_name="bonuses", null=True)  # type: ignore
    effect_id: Optional[int]

    outfit: Optional["libkol.Outfit"] = ForeignKeyField(
        "models.Outfit", related_name="bonuses", null=True)  # type: ignore
    outfit_id: Optional[int]

    familiar: Optional["libkol.Familiar"] = ForeignKeyField(
        "models.Familiar", related_name="passive_bonuses",
        null=True)  # type: ignore
    familiar_id: Optional[int]

    throne_familiar: Optional["libkol.Familiar"] = ForeignKeyField(
        "models.Familiar", related_name="throne_bonus",
        null=True)  # type: ignore
    throne_familiar_id: Optional[int]

    modifier: Modifier = EnumField(enum_type=Modifier)  # type: ignore
    numeric_value: Optional[int] = IntField(null=True)  # type: ignore
    string_value: str = CharField(max_length=255, null=True)  # type: ignore
    percentage: bool = BooleanField(default=False)  # type: ignore
    expression_value: Optional[str] = PickleField(null=True)  # type: ignore

    async def get_value(
        self,
        normalise: bool = False,
        smithsness: Optional[int] = None,
        familiar_weight: Optional[int] = None,
        hobo_power: Optional[int] = None,
    ):
        kol = self.kol

        if self.string_value:
            return 1

        if self.numeric_value:
            if self.percentage is False:
                return self.numeric_value

            return self.modifier.apply_percentage(kol,
                                                  self.numeric_value / 100)

        if self.expression_value:
            subs = {}

            if familiar_weight is not None:
                subs["W"] = familiar_weight

            if smithsness is not None:
                subs["K"] = smithsness

            if hobo_power is not None:
                subs["H"] = hobo_power

            return await expression.evaluate(kol, self.expression_value, subs)

        return 0
示例#26
0
文件: Item.py 项目: mafia4life/libkol
class Item(Model, metaclass=ItemMeta):
    id: int = IntField(pk=True, generated=False)  # type: ignore
    name: str = CharField(max_length=255)  # type: ignore
    desc_id: int = IntField()  # type: ignore
    plural: str = CharField(max_length=255, null=True)  # type: ignore
    image: str = CharField(max_length=255)  # type: ignore
    autosell_value: int = IntField(default=0)  # type: ignore
    level_required: int = IntField(default=0)  # type: ignore

    # Consumables
    food: bool = BooleanField(default=False)  # type: ignore
    fullness: int = IntField(default=0)  # type: ignore
    booze: bool = BooleanField(default=False)  # type: ignore
    inebriety: int = IntField(default=0)  # type: ignore
    spleen: bool = BooleanField(default=False)  # type: ignore
    spleenhit: int = IntField(default=0)  # type: ignore
    quality: str = CharField(max_length=255, null=True)  # type: ignore
    gained_adventures_min: int = IntField(default=0)  # type: ignore
    gained_adventures_max: int = IntField(default=0)  # type: ignore
    gained_muscle_min: int = IntField(default=0)  # type: ignore
    gained_muscle_max: int = IntField(default=0)  # type: ignore
    gained_mysticality_min: int = IntField(default=0)  # type: ignore
    gained_mysticality_max: int = IntField(default=0)  # type: ignore
    gained_moxie_min: int = IntField(default=0)  # type: ignore
    gained_moxie_max: int = IntField(default=0)  # type: ignore

    # Usability
    usable: bool = BooleanField(default=False)  # type: ignore
    multiusable: bool = BooleanField(default=False)  # type: ignore
    combat_usable: bool = BooleanField(default=False)  # type: ignore
    reusable: bool = BooleanField(default=False)  # type: ignore
    combat_reusable: bool = BooleanField(default=False)  # type: ignore
    # Can be used on others
    curse: bool = BooleanField(default=False)  # type: ignore

    # Equipment
    hat: bool = BooleanField(default=False)  # type: ignore
    pants: bool = BooleanField(default=False)  # type: ignore
    shirt: bool = BooleanField(default=False)  # type: ignore
    weapon: bool = BooleanField(default=False)  # type: ignore
    weapon_hands: Optional[int] = IntField(null=True)  # type: ignore
    weapon_type: Optional[str] = CharField(max_length=255,
                                           null=True)  # type: ignore
    offhand: bool = BooleanField(default=False)  # type: ignore
    offhand_type: Optional[str] = CharField(max_length=255,
                                            null=True)  # type: ignore
    accessory: bool = BooleanField(default=False)  # type: ignore
    container: bool = BooleanField(default=False)  # type: ignore
    sixgun: bool = BooleanField(default=False)  # type: ignore
    familiar_equipment: bool = BooleanField(default=False)  # type: ignore
    power: Optional[int] = IntField(null=True)  # type: ignore
    required_muscle: int = IntField(default=0)  # type: ignore
    required_mysticality: int = IntField(default=0)  # type: ignore
    required_moxie: int = IntField(default=0)  # type: ignore
    required_class: Optional[CharacterClass] = EnumField(
        enum_type=CharacterClass, null=True)  # type: ignore
    notes: str = CharField(max_length=255, default="")  # type: ignore

    # Collections
    foldgroup: Optional["libkol.FoldGroup"] = ForeignKeyField(
        "models.FoldGroup", related_name="items", null=True)  # type: ignore
    foldgroup_id: Optional[int]
    zapgroup: Optional["libkol.ZapGroup"] = ForeignKeyField(
        "models.ZapGroup", related_name="items", null=True)  # type: ignore
    zapgroup_id: Optional[int]

    outfit_variants = ManyToManyField("models.OutfitVariant",
                                      related_name="pieces",
                                      null=True)

    # NPC Store Info
    store_row: Optional[int] = IntField(null=True)  # type: ignore
    store_price: Optional[int] = IntField(null=True)  # type: ignore
    store: Optional["libkol.Store"] = ForeignKeyField(
        "models.Store", related_name="items", null=True)  # type: ignore
    store_id: Optional[int]

    # Flags
    hatchling: bool = BooleanField(default=False)  # type: ignore
    pokepill: bool = BooleanField(default=False)  # type: ignore
    sticker: bool = BooleanField(default=False)  # type: ignore
    card: bool = BooleanField(default=False)  # type: ignore
    folder: bool = BooleanField(default=False)  # type: ignore
    bootspur: bool = BooleanField(default=False)  # type: ignore
    bootskin: bool = BooleanField(default=False)  # type: ignore
    food_helper: bool = BooleanField(default=False)  # type: ignore
    booze_helper: bool = BooleanField(default=False)  # type: ignore
    guardian: bool = BooleanField(default=False)  # type: ignore
    single_equip: bool = BooleanField(default=True)  # type: ignore
    # Can appear as a bounty item
    bounty: bool = BooleanField(default=False)  # type: ignore
    # 0: n/a, 1: simple, 2: complex
    candy: int = IntField()  # type: ignore
    # What is this for?
    sphere: bool = BooleanField(default=False)  # type: ignore
    # is a quest item
    quest: bool = BooleanField(default=False)  # type: ignore
    # is a gift item
    gift: bool = BooleanField(default=False)  # type: ignore
    # is tradeable
    tradeable: bool = BooleanField(default=False)  # type: ignore
    # is discardable
    discardable: bool = BooleanField(default=False)  # type: ignore
    # is considered salad when consumed
    salad: bool = BooleanField(default=False)  # type: ignore
    # is considered beer when consumed
    beer: bool = BooleanField(default=False)  # type: ignore
    # is considered wine when consumed
    wine: bool = BooleanField(default=False)  # type: ignore
    # is considered martini when consumed
    martini: bool = BooleanField(default=False)  # type: ignore
    # is considered saucy when consumed
    saucy: bool = BooleanField(default=False)  # type: ignore
    # is considered lasagna when consumed
    lasagna: bool = BooleanField(default=False)  # type: ignore
    # is considered pasta when consumed
    pasta: bool = BooleanField(default=False)  # type: ignore

    @property
    def adventures(self):
        return (self.gained_adventures_min + self.gained_adventures_max) / 2

    def pluralize(self):
        return "{}s".format(self.name) if self.plural is None else self.plural

    @property
    def space(self):
        s = (self.fullness if self.food else self.inebriety
             if self.booze else self.spleenhit if self.spleen else None)

        if s is None:
            raise WrongKindOfItemError("You cannot consume this item")

        return s

    async def autosell(self, quantity: int = 1):
        return await request.autosell_items(self.kol, [self]).parse()

    @property
    def cleans_organ(self) -> Optional[Tuple[int, str]]:
        m = re.match(r"-(\d+) spleen", self.notes)

        if m is None:
            return None

        return (int(m.group(1)), "spleen")

    async def consume(self,
                      utensil: Optional["Item"] = None
                      ) -> parsing.ResourceGain:
        if self.food:
            return await request.eat(self.kol, self, utensil=utensil).parse()
        elif self.booze:
            return await request.drink(self.kol, self, utensil=utensil).parse()
        elif self.spleen:
            return await request.chew(self.kol, self).parse()
        else:
            raise WrongKindOfItemError("You cannot consume this item")

    @classmethod
    async def get_or_discover(cls, *args, **kwargs) -> "Item":
        result = await cls.filter(*args, **kwargs).first()

        if result is None:
            id: int = kwargs.get("id", None)
            desc_id: int = kwargs.get("desc_id", None)

            return await cls.discover(id=id, desc_id=desc_id)

        return result

    @classmethod
    async def discover(cls, id: int = None, desc_id: int = None):
        """
        Discover this item using its id or description id. The description id is preferred as
        it provides more information, so if only an id is provided, libkol will first determine
        the desc_id.

        Note that this Returns an Item object but it is not automatically committed to the database.

        :param id: Id of the item to discover
        :param desc_id: Description id of the item to discover
        """
        if id is not None:
            desc_id = (await request.item_information(cls.kol,
                                                      id).parse()).descid

        if desc_id is None:
            raise ItemNotFoundError(
                "Cannot discover an item without either an id or a desc_id")

        info = await request.item_description(cls.kol, desc_id).parse()
        return Item(**{k: v for k, v in info.items() if v is not None})

    @property
    def type(self):
        types = [
            "hat",
            "shirt",
            "weapon",
            "offhand",
            "pants",
            "familiar_equipment",
            "accessory",
        ]
        return next((t for t in types if getattr(self, t)), "other")

    @property
    def slot(self) -> Optional[Slot]:
        return Slot.from_db(self.type)

    async def get_description(self):
        return await request.item_description(self.kol, self.desc_id).parse()

    async def get_mall_price(self, limited: bool = False) -> Optional[int]:
        """
        Get the lowest price for this item in the mall

        :param limited: Include limited sales in this search
        """
        prices = await request.mall_price(self.kol, self).parse()

        if limited and len(prices.limited) > 0:
            return prices.limited[0].price

        if len(prices.unlimited) > 0:
            return prices.unlimited[0].price

        return None

    async def get_cf_price(self, days: int = 30) -> Optional[int]:
        """
        Get the average transaction price from Coldfront logs

        :param days: Number of days of transactions to consider (default 30)
        """
        ts = int(time.time())
        params = {
            "itemid": self.id,
            "starttime": ts - 60 * 68 * 24 * days,
            "endtime": ts,
        }
        response = await self.kol.request(
            "http://kol.coldfront.net/newmarket/translist.php",
            "GET",
            params=params)
        result = await response.text()

        transactions = [
            parsing.to_float(t[(t.rfind("@") + 1):])
            for t in result[result.find("\n"):].split("\n")
            if t not in ["", "."]
        ]

        return int(mean(transactions)) if len(transactions) > 0 else None

    async def get_mall_listings(self, **kwargs) -> List["types.Listing"]:
        return await request.mall_search(self.kol, query=self,
                                         **kwargs).parse()

    async def buy_from_mall(
        self,
        listing: "types.Listing" = None,
        store_id: int = None,
        price: int = 0,
        quantity: int = 1,
    ):
        if listing is None and store_id is None:
            listings = await self.get_mall_listings(num_results=quantity,
                                                    max_price=price)

            tasks = []  # type: List[Coroutine]

            for l in listings:
                q = min(quantity, (l.limit if l.limit > 0 else quantity),
                        l.stock)
                tasks += [
                    request.mall_purchase(self.kol,
                                          item=self,
                                          listing=l,
                                          quantity=q).parse()
                ]
                quantity -= q

            return await asyncio.gather(*tasks)

        return await request.mall_purchase(
            self.kol,
            item=self,
            listing=listing,
            store_id=store_id,
            price=price,
            quantity=quantity,
        ).parse()

    async def acquire(self, quantity: int = 1):
        need = quantity - self.amount

        if need > 0:
            await self.buy_from_mall(quantity=need)

        return True

    @property
    def amount(self):
        return self.kol.inventory[self] + list(
            self.kol.equipment.values()).count(self)

    def equipped(self):
        return self in self.kol.equipment.values()

    async def equip(self, slot: Optional[Slot] = None) -> bool:
        actual_slot = self.slot if slot is None else slot

        if actual_slot is None:
            raise WrongKindOfItemError("This item cannot be equipped")

        curr = self.kol.equipment

        # If it's already there don't worry
        if curr[actual_slot] == self:
            return True

        # If user didn't specify an accessory and we have it in a slot, don't worry
        if (actual_slot is Slot.Acc1 and slot is None
                and (curr[Slot.Acc2] == self or curr[Slot.Acc3] == self)):
            return True

        return await request.equip(self.kol, self, actual_slot).parse()

    def have(self):
        return self.amount > 0

    def meet_requirements(self):
        return (self.kol.level >= self.level_required
                and self.kol.get_stat(Stat.Muscle) >= self.required_muscle
                and self.kol.get_stat(
                    Stat.Mysticality) >= self.required_mysticality
                and self.kol.get_stat(Stat.Moxie) >= self.required_moxie)

    async def use(self, quantity: int = 1, multi_use: bool = True):
        if self.usable is False:
            raise WrongKindOfItemError("This item cannot be used")

        if self.multiusable and multi_use and quantity > 1:
            await request.item_multi_use(self.kol, self, quantity).parse()
            return

        tasks = [
            request.item_use(self.kol, self).parse() for _ in range(quantity)
        ]
        return await asyncio.gather(*tasks)