Source code for woob.capabilities.rpg

# Copyright(C) 2019-2020 CĂ©lande Adrien
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.


from woob.capabilities.base import find_object

from .base import (
    BaseObject,
    Field, StringField,  BoolField,
    EnumField, Enum,
    UserError,
)
from .collection import CapCollection

__all__ = ['CapRPG', 'Character', 'Skill', 'CharacterClass', 'CollectableItem']


class CharacterNotFound(UserError):
    """ Raised when a character is not found """
    def __init__(self, msg='Character not found'):
        super(CharacterNotFound, self).__init__(msg)


class SkillNotFound(UserError):
    """ Raised when a skill is not found """
    def __init__(self, msg='Skill not found'):
        super(SkillNotFound, self).__init__(msg)


class CharacterClassNotFound(UserError):
    """ Raised when a class is not found """
    def __init__(self, msg='Class not found'):
        super(CharacterClassNotFound, self).__init__(msg)


class CollectableItemNotFound(UserError):
    """ Raised when an item is not found """
    def __init__(self, msg='Item not found'):
        super(CollectableItemNotFound, self).__init__(msg)


class ListField(Field):
    """ Field made of a list """
    def __init__(self, doc, **kwargs):
        if 'default' not in kwargs:
            kwargs['default'] = []
        super(ListField, self).__init__(doc, list, **kwargs)


class DictField(Field):
    """ Field made of a dict """
    def __init__(self, doc, **kwargs):
        if 'default' not in kwargs:
            kwargs['default'] = {}
        super(DictField, self).__init__(doc, dict, **kwargs)


class BaseRPGObject(BaseObject):
    """ Object used to build up all the objects of the CapRPG """
    # TODO: check id and origin for duplicates
    name = StringField('Name', mandatory=True)
    description = StringField('Description', mandatory=False)
    origin = StringField('From which game/platform the object comes from', mandatory=False)
    picture = StringField('URL of a picture', mandatory=False)


[docs]class CharacterClass(BaseRPGObject): """ CharacterClass of a character """ pass
class SkillType(Enum): """ Types of skill """ UNKNOWN = 0 """UNKNOWN: Unknown type""" PASSIVE = 1 """PASSIVE: The effects of the skill are always on. The skill does not need to be activated.""" ACTIVE = 2 """ACTIVE: The skill must be activated.""" class SkillTarget(Enum): """ Target of a skill """ UNKNOWN = 0 """UNKNOWN: Unknown target""" SELF = 1 """SELF: The target is the one that launched it""" FOE = 2 """FOE: The target is a different character than the one who launched it""" SELF_AND_FOE = 3 """SELF_AND_FOE: The target is a different character and the one who lanched it""" FIELD = 4 """FIELD: The target is the field or the environment""" class SkillCategory(Enum): """ Category of a skill """ UNKNOWN = 0 """UNKNOWN: Unknown category""" PHYSICAL = 1 """PHYSICAL: The skill is meant to deal physical damages (and effects)""" MAGICAL = 2 """MAGICAL: The skill is meant to deal magical or special damages (and effects)""" PHYSICAL_AND_MAGICAL = 3 """PHYSICAL_AND_MAGICAM: The skill is meant to deal physical and magical damages (and effects)""" STATUS = 4 """STATUS: The skill does not deal direct damages."""
[docs]class Skill(BaseRPGObject): """ Skill of a character """ type = EnumField('Type of skill', SkillType, mandatory=True, default=SkillType.UNKNOWN) target = EnumField('Target of the skill', SkillTarget, mandatory=True, default=SkillTarget.UNKNOWN) statistics = DictField('Dict of statistics', mandatory=False) character_classes = ListField('List of CharacterClass ids that can use this move', mandatory=False) category = EnumField('Category of skill', SkillCategory, mandatory=False)
[docs]class Character(BaseRPGObject): """ Creature or person """ base_stats = DictField('Base statistics') character_classes = ListField('List of CharacterClasses id', mandatory=False) skills = ListField('List of Skills id', mandatory=False) next_forms = ListField('List of the next forms of the character', mandatory=False) locations = ListField('List of locations of the character', mandatory=False)
[docs]class CollectableItem(BaseRPGObject): """ Object that you can find in the game """ to_use = BoolField('The object can be used at anytime', mandatory=False) to_carry = BoolField('The object must be carried to be used (like in battle)', mandatory=False) category = StringField('Category of the item', mandatory=False) locations = ListField('List of locations of the item', mandatory=False)
[docs]class CapRPG(CapCollection): """ Capability for rpg games to list characters, objects, etc. """
[docs] def iter_resources(self, objs, split_path): """ Iter reources. return :func:`iter_characters` for 'character' """ if Character in objs: self._restrict_level(split_path) return self.iter_characters()
[docs] def iter_characters(self): """ Iter characters. :rtype: iter[:class: `Character`] """ raise NotImplementedError()
[docs] def get_character(self, character_id): """ Get a character with its ID. :param character_id: ID of the character :type character_id: :class:`str` :rtype: :class: `Character` :raises: :class: `CharcterNotFound` """ # TODO: find from id and version? return find_object(self.iter_characters(), id=character_id, error=CharacterNotFound)
[docs] def iter_skills(self, skill_type=None): """ Iter all available skills. :param skill_type: Type of skill :type skill_type: :class:`int` :rtype: iter[:class: `Skill`] """ raise NotImplementedError()
[docs] def get_skill(self, skill_id): """ Get a skill from with ID. :param skill_id: ID of the skill :type skill_id: :class:`str` :rtype: :class: `Skill` :raises: :class: `SkillNotFound` """ return find_object(self.iter_skills(), id=skill_id, error=SkillNotFound)
[docs] def iter_skill_set(self, character_id, skill_type=None): """ Iter skills for a specific character :param character_id: ID of the character :type character_id: :class:`str` :param skill_type: Type of skill :type skill_type: :class:`int` :rtype: :class: iter[:class: `Skill`] """ raise NotImplementedError()
[docs] def iter_character_classes(self): """ Iter all classes :rtype: :class: iter[:class: `CharacterClass`] """ raise NotImplementedError()
[docs] def get_character_class(self, class_id): """ Get details of a class according to id :param class_id: ID of the skill :type class_id: :class:`str` :rtype: :class: `CharacterClass` :raises: :class: `CharacterClassNotFound` """ return find_object(self.iter_character_classes(), id=class_id, error=CharacterClassNotFound)
[docs] def iter_collectable_items(self): """ Iter all collectable items :rtype: :class: iter[:class: `CollectableItem`] """ raise NotImplementedError()
[docs] def get_collectable_item(self, item_id): """ Get details of a collectable item according to id :param item_id: ID of the skill :type item_id: :class:`str` :rtype: :class: `CollectableItem` :raises: :class: `CollectableItemNotFound` """ return find_object(self.iter_collectable_items(), id=item_id, error=CollectableItemNotFound)