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, BoolField, Enum, EnumField, Field, StringField, 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().__init__(msg)


class SkillNotFound(UserError):
    """Raised when a skill is not found"""

    def __init__(self, msg="Skill not found"):
        super().__init__(msg)


class CharacterClassNotFound(UserError):
    """Raised when a class is not found"""

    def __init__(self, msg="Class not found"):
        super().__init__(msg)


class CollectableItemNotFound(UserError):
    """Raised when an item is not found"""

    def __init__(self, msg="Item not found"):
        super().__init__(msg)


class ListField(Field):
    """Field made of a list"""

    def __init__(self, doc, **kwargs):
        if "default" not in kwargs:
            kwargs["default"] = []
        super().__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().__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)