# 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)