# Coverage for thb/characters/suika.py : 100%

## 75 statements 75 run 0 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, ActionShootdown, DrawCards, LaunchCard, Pindian

8 from thb.actions import PrepareStage, UserAction

9 from thb.cards.base import Skill, VirtualCard

10 from thb.cards.classes import AttackCard, TreatAs, WineCard, t_None, t_OtherOne

11 from thb.characters.base import Character, register_character_to

12 from thb.mode import THBEventHandler

13

14

15# -- code --

16 class HeavyDrinkerWine(TreatAs, VirtualCard):

17 treat_as = WineCard

18

19

20 class HeavyDrinkerFailed(ActionShootdown):

21 pass

22

23

24 class HeavyDrinkerAction(UserAction):

25 def apply_action(self):

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

27 g = self.game

28 src.tags['suika_target'].append(tgt)

29 if g.process_action(Pindian(src, tgt)):

30 g.process_action(LaunchCard(src, [src], HeavyDrinkerWine(src), bypass_check=True))

31 g.process_action(LaunchCard(tgt, [tgt], HeavyDrinkerWine(src), bypass_check=True))

32

33 else:

34 src.tags['suika_failed'] = src.tags['turn_count']

35

36 return True

37

38 def is_valid(self):

39 tags = self.source.tags

40 if tags['suika_failed'] >= tags['turn_count']:

41 raise HeavyDrinkerFailed

42

43 if self.target in tags['suika_target']:

44 raise ActionLimitExceeded

45

46 Pindian(self.source, self.target).action_shootdown_exception()

47

48 return True

49

50

51 class HeavyDrinker(Skill):

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

53 associated_action = HeavyDrinkerAction

54 target = t_OtherOne()

55

56 def check(self):

57 return not self.associated_cards

58

59

60 class HeavyDrinkerHandler(THBEventHandler):

61 interested = ['action_apply']

62 execute_before = ['WineHandler']

63

64 def handle(self, evt_type, act):

65 if evt_type == 'action_apply' and isinstance(act, PrepareStage):

66 act.target.tags['suika_target'] = []

67

68 return act

69

70

71 class DrunkenDream(Skill):

72 target = t_None()

73 associated_action = None

74 skill_category = ['character', 'passive']

75

76

77 class DrunkenDreamDrawCards(DrawCards):

78 pass

79

80

81 class DrunkenDreamHandler(THBEventHandler):

82 interested = ['action_apply', 'calcdistance']

83 execute_before = ['WineHandler']

84

85 def handle(self, evt_type, act):

86 if evt_type == 'calcdistance':

87 src, card, dist = act

88 if card.is_card(AttackCard):

89 if not src.has_skill(DrunkenDream):

90 return act

91

92 if not src.tags['wine']:

93 return act

94

95 for p in dist:

96 dist[p] -= 2

97

98 elif evt_type == 'action_apply' and isinstance(act, PrepareStage):

99 tgt = act.target

100 if not tgt.has_skill(DrunkenDream):

101 return act

102

103 if not tgt.tags['wine']:

104 return act

105

106 g = self.game

107 g.process_action(DrunkenDreamDrawCards(tgt, 1))

108

109 return act

110

111

112@register_character_to('common')

113 class Suika(Character):

114 skills = [HeavyDrinker, DrunkenDream]

115 eventhandlers = [

116 HeavyDrinkerHandler,

117 DrunkenDreamHandler,

118 ]

119 maxlife = 4