# Coverage for thb/characters/nitori.py : 35%

## 67 statements 29 run 38 missing 0 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# -- third party --

6# -- own --

7 from thb.actions import ActionLimitExceeded, DrawCards, LaunchCard, PlayerTurn, Reforge, UserAction

8 from thb.actions import random_choose_card, ttags

9 from thb.cards.base import PhysicalCard, Skill, TreatAs, t_OtherOne

10 from thb.cards.definition import AttackCard

11 from thb.characters.base import Character, register_character_to

12 from thb.inputlets import ChoosePeerCardInputlet

13 from thb.mode import THBEventHandler

14

15

16# -- code --

17 class DismantleAction(UserAction):

18 def apply_action(self):

19 src, tgt = self.source, self.target

20 ttags(src)['dismantle'] = True

21

22 g = self.game

23 c = g.user_input([src], ChoosePeerCardInputlet(self, tgt, ('equips', )))

24 c = c or random_choose_card(g, [tgt.equips])

25 if not c: return False

26

27 g.process_action(Reforge(src, tgt, c))

28 g.process_action(DrawCards(tgt, 1))

29

30 return True

31

32 def is_valid(self):

33 return not ttags(self.source)['dismantle'] and bool(self.target.equips)

34

35

36 class Dismantle(Skill):

37 associated_action = DismantleAction

38 skill_category = ['character', 'active']

39 target = t_OtherOne()

40

41 def check(self):

42 return not self.associated_cards

43

44

45 class Craftsman(TreatAs, Skill):

46 skill_category = ['character', 'active']

47

48 @property

49 def treat_as(self):

50 params = getattr(self, 'action_params', {})

51 return PhysicalCard.classes.get(params.get('treat_as'), AttackCard)

52

53 def check(self):

54 cl = self.associated_cards

55 p = self.character

56

57 if 'basic' not in self.treat_as.category:

58 return False

59

60 if not cl or set(cl) != (set(p.cards) | set(p.showncards)):

61 return False

62

63 return True

64

65 @classmethod

66 def list_treat_as(cls):

67 return [c() for c in PhysicalCard.classes.values() if 'basic' in c.category]

68

69

70 class CraftsmanHandler(THBEventHandler):

71 interested = ['action_after', 'action_shootdown']

72

73 def handle(self, evt_type, act):

74 if evt_type == 'action_after' and isinstance(act, LaunchCard):

75 c = act.card

76 if c.is_card(Craftsman):

77 src = act.source

78 ttags(src)['craftsman'] = True

79

80 elif evt_type == 'action_shootdown':

81 if not isinstance(act, LaunchCard): return act

82 c = act.card

83 if not c.is_card(Craftsman): return act

84 g = self.game

85 try:

86 current = PlayerTurn.get_current(g).target

87 except IndexError:

88 return act

89

90 if ttags(act.source)['craftsman'] and current is act.source:

91 raise ActionLimitExceeded

92

93 return act

94

95

96@register_character_to('common', '-kof')

97 class Nitori(Character):

98 skills = [Dismantle, Craftsman]

99 eventhandlers = [CraftsmanHandler]

100 maxlife = 3