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