# Coverage for thb/characters/sp_aya.py : 25%

## 139 statements 43 run 96 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

3# -- stdlib --

4# -- third party --

5# -- own --

6 from game.base import ActionShootdown, InputTransaction

7 from thb.actions import ActionStage, ActionStageLaunchCard, DrawCards, DropCardStage, FinalizeStage

8 from thb.actions import GenericAction, LaunchCard, PlayerTurn, ShowCards, UserAction, ask_for_action

9 from thb.cards.base import Card, Skill, VirtualCard

10 from thb.cards.classes import PhysicalCard, t_None, t_Self

11 from thb.characters.base import Character, register_character_to

12 from thb.inputlets import ChooseOptionInputlet

13 from thb.mode import THBEventHandler

14

15

16# -- code --

17 class WindWalkLaunch(ActionStageLaunchCard):

18 pass

19

20

21 class WindWalkSkipAction(GenericAction):

22 def apply_action(self) -> bool:

23 g = self.game

24 ActionStage.force_break(g)

25 turn = PlayerTurn.get_current(g)

26 try:

27 turn.pending_stages.remove(DropCardStage)

28 turn.pending_stages.remove(FinalizeStage)

29 except Exception:

30 pass

31

32 return True

33

34

35 class WindWalkAction(UserAction):

36 card_usage = 'launch'

37

38 def apply_action(self):

39 g = self.game

40 tgt = self.target

41

42 while True:

43 dc = DrawCards(tgt, 1)

44 g.process_action(dc)

45 c, = dc.cards

46 self.card = c

47 g.process_action(ShowCards(tgt, [c]))

48

49 with InputTransaction('ActionStageAction', [tgt]) as trans:

50 p, rst = ask_for_action(

51 self, [tgt], ('cards', 'showncards'), g.players, trans=trans

52 )

53

54 if p is not tgt:

55 g.process_action(WindWalkSkipAction(tgt, tgt))

56 break

57

58 assert p

59 assert rst

60

61 cl, tl = rst

62 g.players.reveal(cl)

63 c, = cl

64

65 g.process_action(WindWalkLaunch(p, tl, c))

66

67 return True

68

69 def cond(self, cl):

70 if not (cl and len(cl) == 1):

71 return False

72

73 return bool(cl[0].associated_action) and [self.card] == VirtualCard.unwrap(cl)

74

75 def ask_for_action_verify(self, p, cl, tl):

76 assert len(cl) == 1

77 return WindWalkLaunch(p, tl, cl[0]).can_fire()

78

79 def choose_player_target(self, tl):

80 return tl, True

81

82

83 class WindWalkTargetLimit(ActionShootdown):

84 pass

85

86

87 class WindWalkHandler(THBEventHandler):

88 interested = ['action_apply', 'action_shootdown']

89

90 def handle(self, evt_type, act):

91 if evt_type == 'action_apply' and isinstance(act, LaunchCard):

92 src = act.source

93 if act.card.is_card(WindWalk):

94 return act

95

96 if not src.has_skill(WindWalk):

97 return act

98

99 src.tags['windwalk_last_targets'] = set(act.target_list)

100

101 elif evt_type == 'action_apply' and isinstance(act, PlayerTurn):

102 src = act.source

103 if not src.has_skill(WindWalk):

104 return act

105

106 src.tags['windwalk_last_targets'] = set()

107

108 elif evt_type == 'action_shootdown' and isinstance(act, LaunchCard):

109 g = self.game

110 if not isinstance(g.action_stack[-1], WindWalkAction):

111 return act

112

113 src, tl = act.source, set(act.target_list)

114 last_tl = src.tags['windwalk_last_targets'] or set()

115

116 if not tl <= last_tl:

117 raise WindWalkTargetLimit

118

119 return act

120

121 return act

122

123

124 class WindWalk(Skill):

125 associated_action = WindWalkAction

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

127 target = t_Self()

128 usage = 'drop'

129

130 def check(self):

131 cl = self.associated_cards

132 if not(cl and len(cl) == 1):

133 return False

134

135 if cl[0].is_card(Skill):

136 return False

137

138 return True

139

140

141 class Dominance(Skill):

142 associated_action = None

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

144 target = t_None()

145

146

147 class DominanceAction(PlayerTurn):

148 pass

149

150

151 class DominanceHandler(THBEventHandler):

152 interested = ['action_after', 'action_apply']

153

154 def handle(self, evt_type, act):

155 if evt_type == 'action_apply' and isinstance(act, PlayerTurn):

156 t = act.target.tags

157 t['dominance_suits'] = set()

158 t['dominance_suit_SPADE'] = False

159 t['dominance_suit_CLUB'] = False

160 t['dominance_suit_HEART'] = False

161 t['dominance_suit_DIAMOND'] = False

162

163 elif evt_type == 'action_apply' and isinstance(act, LaunchCard):

164 if not act.source.has_skill(Dominance):

165 return act

166

167 card = act.card

168 if not card.is_card(PhysicalCard):

169 return act

170

171 suit = card.suit

172 if suit not in (Card.SPADE, Card.CLUB, Card.HEART, Card.DIAMOND):

173 return act

174

175 try:

176 t = act.source.tags

177 t['dominance_suits'].add(suit)

178 t['dominance_suit_%s' % Card.SUIT_REV[suit]] = True

179

180 except AttributeError:

181 pass

182

183 elif evt_type == 'action_after' and isinstance(act, PlayerTurn):

184 tgt = act.target

185 if not tgt.has_skill(Dominance):

186 return act

187

188 if len(tgt.tags['dominance_suits'] or set()) != 4:

189 return act

190

191 g = self.game

192 if not g.user_input([tgt], ChooseOptionInputlet(self, (False, True))):

193 return act

194

195 g.process_action(DominanceAction(tgt))

196

197 return act

198

199

200@register_character_to('imperial')

201 class SpAya(Character):

202 skills = [WindWalk, Dominance]

203 eventhandlers = [WindWalkHandler, DominanceHandler]

204 maxlife = 4