Coverage for thb/characters/base.py : 100%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2from __future__ import annotations
4# -- stdlib --
5from collections import defaultdict
6from typing import Any, ClassVar, Dict, Iterable, List, Set, TYPE_CHECKING, Type
8# -- third party --
9# -- own --
10from game.base import GameObject, Player
11from thb.cards.base import CardList, Skill
12from thb.mode import THBEventHandler
13from utils.misc import partition
15# -- typing --
16if TYPE_CHECKING:
17 from thb.meta.typing import CharacterMeta # noqa: F401
20# -- code --
21# common, id8, faith, kof, 3v3, testing
22# -id8, ...
23characters_by_category: Dict[str, Set[Type[Character]]] = defaultdict(set)
26class Character(GameObject):
27 classes: ClassVar[Dict[str, Type[Character]]] = {}
29 # ----- Class Variables -----
30 ui_meta: ClassVar[CharacterMeta]
31 eventhandlers: ClassVar[List[Type[THBEventHandler]]] = ()
32 categories: ClassVar[Iterable[str]] = ()
33 boss_skills: ClassVar[List[Type[Skill]]] = ()
35 skills: List[Type[Skill]] = ()
36 maxlife: int = 0
38 # ----- Instance Variables -----
39 dead: bool
40 life: int
41 disabled_skills: Dict[str, Set[Type[Skill]]]
42 tags: Dict[str, Any]
43 cards: CardList
44 showncards: CardList
45 equips: CardList
46 fatetell: CardList
47 special: CardList
48 showncardlists: List[CardList]
49 player: Player
51 def __init__(self, player: Player):
52 self.player = player
53 self.disabled_skills = defaultdict(set)
55 cls = self.__class__
57 self.skills = list(cls.skills)
58 self.maxlife = cls.maxlife
59 self.life = cls.maxlife
60 self.dead = False
62 self.cards = CardList(self, 'cards') # Cards in hand
63 self.showncards = CardList(self, 'showncards') # Cards which are shown to the others, treated as 'Cards in hand'
64 self.equips = CardList(self, 'equips') # Equipments
65 self.fatetell = CardList(self, 'fatetell') # Cards in the Fatetell Zone
66 self.special = CardList(self, 'special') # used on special purpose
67 self.showncardlists = [self.showncards, self.fatetell]
68 self.tags = defaultdict(int)
70 def get_player(self) -> Player:
71 return self.player
73 def get_skills(self, skill: Type['Skill']):
74 return [s for s in self.skills if issubclass(s, skill)]
76 def has_skill(self, skill: Type['Skill']):
77 if self.dead:
78 return False
80 if any(issubclass(skill, s) for l in self.disabled_skills.values() for s in l):
81 return False
83 return self.get_skills(skill)
85 def disable_skill(self, skill: Type['Skill'], reason: str):
86 self.disabled_skills[reason].add(skill)
88 def reenable_skill(self, reason: str):
89 self.disabled_skills.pop(reason, '')
91 def reveal(self, obj: Any) -> None:
92 self.player.reveal(obj)
94 def __repr__(self) -> str:
95 return '<Char: {}>'.format(self.__class__.__name__)
98def register_character_to(*cats):
99 sets = [characters_by_category[c] for c in set(cats)]
101 def register(cls: Type[Character]):
102 Character.classes[cls.__name__] = cls
104 for s in sets:
105 s.add(cls)
107 cls.categories = cats
108 return cls
110 return register
113def get_characters(*categories):
114 cats: Set[str] = set(categories)
115 chars: Set[Type[Character]] = set()
116 pos, neg = partition(lambda c: not c.startswith('-'), cats)
117 chars.update(*[characters_by_category[c] for c in pos])
118 chars.difference_update(*[characters_by_category['-' + c] for c in pos])
119 chars.difference_update(*[characters_by_category[c.strip('-')] for c in neg])
120 return list(sorted(chars, key=lambda i: i.__name__))