# Coverage for thb/characters/base.py : 66%

## 76 statements 60 run 16 missing 4 excluded 0 partial

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 -*-

2 from __future__ import annotations

3

4# -- stdlib --

5 from collections import defaultdict

6 from typing import Any, ClassVar, Dict, Iterable, List, Set, TYPE_CHECKING, Type

7

8# -- third party --

9# -- own --

10 from game.base import GameObject, Player

11 from thb.cards.base import CardList, Skill

12 from thb.mode import THBEventHandler

13 from utils.misc import partition

14

15# -- typing --

16 if TYPE_CHECKING:

17 from thb.meta.typing import CharacterMeta # noqa: F401

18

19

20# -- code --

21# common, id8, faith, kof, 3v3, testing

22# -id8, ...

23 characters_by_category: Dict[str, Set[Type[Character]]] = defaultdict(set)

24

25

26 class Character(GameObject):

27 classes: ClassVar[Dict[str, Type[Character]]] = {}

28

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]]] = []

34

35 skills: List[Type[Skill]] = []

36 maxlife: int = 0

37

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 lists: List[CardList]

49 player: Player

50

51 def __init__(self, player: Player):

52 self.player = player

53 self.disabled_skills = defaultdict(set)

54

55 cls = self.__class__

56

57 self.skills = list(cls.skills)

58 self.maxlife = cls.maxlife

59 self.life = cls.maxlife

60 self.dead = False

61

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.lists = [

68 self.cards,

69 self.showncards,

70 self.equips,

71 self.fatetell,

72 self.special,

73 ]

74 self.tags = defaultdict(int)

75

76 self._: dict = {}

77

78 def get_player(self) -> Player:

79 return self.player

80

81 def get_skills(self, skill: Type['Skill']):

82 return [s for s in self.skills if issubclass(s, skill)]

83

84 def has_skill(self, skill: Type['Skill']):

85 if self.dead:

86 return False

87

88 if any(issubclass(skill, s) for l in self.disabled_skills.values() for s in l):

89 return False

90

91 return self.get_skills(skill)

92

93 def disable_skill(self, skill: Type['Skill'], reason: str):

94 self.disabled_skills[reason].add(skill)

95

96 def reenable_skill(self, reason: str):

97 self.disabled_skills.pop(reason, '')

98

99 def reveal(self, obj: Any) -> None:

100 self.player.reveal(obj)

101

102 def __repr__(self) -> str:

103 return '<Char: {}>'.format(self.__class__.__name__)

104

105

106 def register_character_to(*cats):

107 sets = [characters_by_category[c] for c in set(cats)]

108

109 def register(cls: Type[Character]):

110 Character.classes[cls.__name__] = cls

111

112 for s in sets:

113 s.add(cls)

114

115 cls.categories = cats

116 return cls

117

118 return register

119

120

121 def get_characters(*categories):

122 cats: Set[str] = set(categories)

123 chars: Set[Type[Character]] = set()

124 pos, neg = partition(lambda c: not c.startswith('-'), cats)

125 chars.update(*[characters_by_category[c] for c in pos])

126 chars.difference_update(*[characters_by_category['-' + c] for c in pos])

127 chars.difference_update(*[characters_by_category[c.strip('-')] for c in neg])

128 return list(sorted(chars, key=lambda i: i.__name__))